diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index c430854265..cc906eaf6d 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -46,13 +46,6 @@ jobs: python-version: [ "3.14" ] pydantic-version: [ "pydantic>=2.0.2,<3.0.0" ] include: - - os: macos-latest - python-version: "3.8" - pydantic-version: "pydantic>=1.10.0,<2.0.0" - - os: windows-latest - python-version: "3.8" - pydantic-version: "pydantic>=2.0.2,<3.0.0" - coverage: coverage - os: ubuntu-latest python-version: "3.9" pydantic-version: "pydantic>=1.10.0,<2.0.0" @@ -73,6 +66,10 @@ jobs: python-version: "3.13" pydantic-version: "pydantic>=2.0.2,<3.0.0" coverage: coverage + - os: ubuntu-latest + python-version: "3.13" + pydantic-version: "pydantic>=2.0.2,<3.0.0" + coverage: coverage - os: ubuntu-latest python-version: "3.14" pydantic-version: "pydantic>=2.0.2,<3.0.0" @@ -101,16 +98,21 @@ jobs: run: uv pip install -r requirements-tests.txt - name: Install Pydantic run: uv pip install "${{ matrix.pydantic-version }}" - # TODO: Remove this once Python 3.8 is no longer supported - - name: Install older AnyIO in Python 3.8 - if: matrix.python-version == '3.8' - run: uv pip install "anyio[trio]<4.0.0" - run: mkdir coverage - name: Test run: bash scripts/test.sh env: COVERAGE_FILE: coverage/.coverage.${{ runner.os }}-py${{ matrix.python-version }} CONTEXT: ${{ runner.os }}-py${{ matrix.python-version }} + - name: CodSpeed benchmarks + if: matrix.os == 'ubuntu-latest' && matrix.python-version == '3.13' && matrix.pydantic-version == 'pydantic>=2.0.2,<3.0.0' + uses: CodSpeedHQ/action@v4 + env: + COVERAGE_FILE: coverage/.coverage.${{ runner.os }}-py${{ matrix.python-version }} + CONTEXT: ${{ runner.os }}-py${{ matrix.python-version }} + with: + mode: simulation + run: coverage run -m pytest tests/ --codspeed # Do not store coverage for all possible combinations to avoid file size max errors in Smokeshow - name: Store coverage files if: matrix.coverage == 'coverage' @@ -131,7 +133,7 @@ jobs: - uses: actions/checkout@v6 - uses: actions/setup-python@v6 with: - python-version: '3.8' + python-version: '3.11' - name: Setup uv uses: astral-sh/setup-uv@v7 with: diff --git a/.gitignore b/.gitignore index 6016ffa598..3dc12ca951 100644 --- a/.gitignore +++ b/.gitignore @@ -31,3 +31,5 @@ archive.zip # Ignore while the setup still depends on requirements.txt files uv.lock + +.codspeed diff --git a/docs/de/docs/advanced/additional-responses.md b/docs/de/docs/advanced/additional-responses.md index 29a0a14777..0f9b122516 100644 --- a/docs/de/docs/advanced/additional-responses.md +++ b/docs/de/docs/advanced/additional-responses.md @@ -26,7 +26,7 @@ Jedes dieser Response-`dict`s kann einen Schlüssel `model` haben, welcher ein P Um beispielsweise eine weitere Response mit dem Statuscode `404` und einem Pydantic-Modell `Message` zu deklarieren, können Sie schreiben: -{* ../../docs_src/additional_responses/tutorial001.py hl[18,22] *} +{* ../../docs_src/additional_responses/tutorial001_py39.py hl[18,22] *} /// note | Hinweis @@ -203,7 +203,7 @@ Sie können beispielsweise eine Response mit dem Statuscode `404` deklarieren, d Und eine Response mit dem Statuscode `200`, die Ihr `response_model` verwendet, aber ein benutzerdefiniertes Beispiel (`example`) enthält: -{* ../../docs_src/additional_responses/tutorial003.py hl[20:31] *} +{* ../../docs_src/additional_responses/tutorial003_py39.py hl[20:31] *} Es wird alles kombiniert und in Ihre OpenAPI eingebunden und in der API-Dokumentation angezeigt: diff --git a/docs/de/docs/advanced/async-tests.md b/docs/de/docs/advanced/async-tests.md index ad82452052..7206f136fd 100644 --- a/docs/de/docs/advanced/async-tests.md +++ b/docs/de/docs/advanced/async-tests.md @@ -32,11 +32,11 @@ Betrachten wir als einfaches Beispiel eine Dateistruktur ähnlich der in [Größ Die Datei `main.py` hätte als Inhalt: -{* ../../docs_src/async_tests/main.py *} +{* ../../docs_src/async_tests/app_a_py39/main.py *} Die Datei `test_main.py` hätte die Tests für `main.py`, das könnte jetzt so aussehen: -{* ../../docs_src/async_tests/test_main.py *} +{* ../../docs_src/async_tests/app_a_py39/test_main.py *} ## Es ausführen { #run-it } @@ -56,7 +56,7 @@ $ pytest Der Marker `@pytest.mark.anyio` teilt pytest mit, dass diese Testfunktion asynchron aufgerufen werden soll: -{* ../../docs_src/async_tests/test_main.py hl[7] *} +{* ../../docs_src/async_tests/app_a_py39/test_main.py hl[7] *} /// tip | Tipp @@ -66,7 +66,7 @@ Beachten Sie, dass die Testfunktion jetzt `async def` ist und nicht nur `def` wi Dann können wir einen `AsyncClient` mit der App erstellen und mit `await` asynchrone Requests an ihn senden. -{* ../../docs_src/async_tests/test_main.py hl[9:12] *} +{* ../../docs_src/async_tests/app_a_py39/test_main.py hl[9:12] *} Das ist das Äquivalent zu: diff --git a/docs/de/docs/advanced/behind-a-proxy.md b/docs/de/docs/advanced/behind-a-proxy.md index 183d0beeef..1c74590503 100644 --- a/docs/de/docs/advanced/behind-a-proxy.md +++ b/docs/de/docs/advanced/behind-a-proxy.md @@ -44,7 +44,7 @@ $ fastapi run --forwarded-allow-ips="*" Angenommen, Sie definieren eine *Pfadoperation* `/items/`: -{* ../../docs_src/behind_a_proxy/tutorial001_01.py hl[6] *} +{* ../../docs_src/behind_a_proxy/tutorial001_01_py39.py hl[6] *} Wenn der Client versucht, zu `/items` zu gehen, würde er standardmäßig zu `/items/` umgeleitet. @@ -115,7 +115,7 @@ In diesem Fall würde der ursprüngliche Pfad `/app` tatsächlich unter `/api/v1 Auch wenn Ihr gesamter Code unter der Annahme geschrieben ist, dass es nur `/app` gibt. -{* ../../docs_src/behind_a_proxy/tutorial001.py hl[6] *} +{* ../../docs_src/behind_a_proxy/tutorial001_py39.py hl[6] *} Und der Proxy würde das **Pfadpräfix** on-the-fly **„entfernen“**, bevor er den Request an den Anwendungsserver (wahrscheinlich Uvicorn via FastAPI CLI) übermittelt, dafür sorgend, dass Ihre Anwendung davon überzeugt ist, dass sie unter `/app` bereitgestellt wird, sodass Sie nicht Ihren gesamten Code dahingehend aktualisieren müssen, das Präfix `/api/v1` zu verwenden. @@ -193,7 +193,7 @@ Sie können den aktuellen `root_path` abrufen, der von Ihrer Anwendung für jede Hier fügen wir ihn, nur zu Demonstrationszwecken, in die Nachricht ein. -{* ../../docs_src/behind_a_proxy/tutorial001.py hl[8] *} +{* ../../docs_src/behind_a_proxy/tutorial001_py39.py hl[8] *} Wenn Sie Uvicorn dann starten mit: @@ -220,7 +220,7 @@ wäre die Dictionary mit Modellen für maschinelles Lernen einfügen. Dieser Code wird ausgeführt, **bevor** die Anwendung **beginnt, Requests entgegenzunehmen**, während des *Startups*. @@ -48,7 +48,7 @@ Möglicherweise müssen Sie eine neue Version starten, oder Sie haben es einfach Das Erste, was auffällt, ist, dass wir eine asynchrone Funktion mit `yield` definieren. Das ist sehr ähnlich zu Abhängigkeiten mit `yield`. -{* ../../docs_src/events/tutorial003.py hl[14:19] *} +{* ../../docs_src/events/tutorial003_py39.py hl[14:19] *} Der erste Teil der Funktion, vor dem `yield`, wird ausgeführt **bevor** die Anwendung startet. @@ -60,7 +60,7 @@ Wie Sie sehen, ist die Funktion mit einem `@asynccontextmanager` versehen. Dadurch wird die Funktion in einen sogenannten „**asynchronen Kontextmanager**“ umgewandelt. -{* ../../docs_src/events/tutorial003.py hl[1,13] *} +{* ../../docs_src/events/tutorial003_py39.py hl[1,13] *} Ein **Kontextmanager** in Python ist etwas, das Sie in einer `with`-Anweisung verwenden können, zum Beispiel kann `open()` als Kontextmanager verwendet werden: @@ -82,7 +82,7 @@ In unserem obigen Codebeispiel verwenden wir ihn nicht direkt, sondern übergebe Der Parameter `lifespan` der `FastAPI`-App benötigt einen **asynchronen Kontextmanager**, wir können ihm also unseren neuen asynchronen Kontextmanager `lifespan` übergeben. -{* ../../docs_src/events/tutorial003.py hl[22] *} +{* ../../docs_src/events/tutorial003_py39.py hl[22] *} ## Alternative Events (deprecatet) { #alternative-events-deprecated } @@ -104,7 +104,7 @@ Diese Funktionen können mit `async def` oder normalem `def` deklariert werden. Um eine Funktion hinzuzufügen, die vor dem Start der Anwendung ausgeführt werden soll, deklarieren Sie diese mit dem Event `startup`: -{* ../../docs_src/events/tutorial001.py hl[8] *} +{* ../../docs_src/events/tutorial001_py39.py hl[8] *} In diesem Fall initialisiert die Eventhandler-Funktion `startup` die „Datenbank“ der Items (nur ein `dict`) mit einigen Werten. @@ -116,7 +116,7 @@ Und Ihre Anwendung empfängt erst dann Requests, wenn alle `startup`-Eventhandle Um eine Funktion hinzuzufügen, die beim Shutdown der Anwendung ausgeführt werden soll, deklarieren Sie sie mit dem Event `shutdown`: -{* ../../docs_src/events/tutorial002.py hl[6] *} +{* ../../docs_src/events/tutorial002_py39.py hl[6] *} Hier schreibt die `shutdown`-Eventhandler-Funktion eine Textzeile `"Application shutdown"` in eine Datei `log.txt`. diff --git a/docs/de/docs/advanced/generate-clients.md b/docs/de/docs/advanced/generate-clients.md index d8836295b6..659343f5bc 100644 --- a/docs/de/docs/advanced/generate-clients.md +++ b/docs/de/docs/advanced/generate-clients.md @@ -167,7 +167,7 @@ Aber für den generierten Client könnten wir die OpenAPI-Operation-IDs direkt v Wir könnten das OpenAPI-JSON in eine Datei `openapi.json` herunterladen und dann mit einem Skript wie dem folgenden **den präfixierten Tag entfernen**: -{* ../../docs_src/generate_clients/tutorial004.py *} +{* ../../docs_src/generate_clients/tutorial004_py39.py *} //// tab | Node.js diff --git a/docs/de/docs/advanced/middleware.md b/docs/de/docs/advanced/middleware.md index 8396a626b6..ccc6a64c3b 100644 --- a/docs/de/docs/advanced/middleware.md +++ b/docs/de/docs/advanced/middleware.md @@ -57,13 +57,13 @@ Erzwingt, dass alle eingehenden geparst, sondern direkt als `bytes` gelesen und die Funktion `magic_data_reader()` wäre dafür verantwortlich, ihn in irgendeiner Weise zu parsen. diff --git a/docs/de/docs/advanced/response-change-status-code.md b/docs/de/docs/advanced/response-change-status-code.md index b079e241d1..b209c2d671 100644 --- a/docs/de/docs/advanced/response-change-status-code.md +++ b/docs/de/docs/advanced/response-change-status-code.md @@ -20,7 +20,7 @@ Sie können einen Parameter vom Typ `Response` in Ihrer *Pfadoperation-Funktion* Anschließend können Sie den `status_code` in diesem *vorübergehenden* Response-Objekt festlegen. -{* ../../docs_src/response_change_status_code/tutorial001.py hl[1,9,12] *} +{* ../../docs_src/response_change_status_code/tutorial001_py39.py hl[1,9,12] *} Und dann können Sie jedes benötigte Objekt zurückgeben, wie Sie es normalerweise tun würden (ein `dict`, ein Datenbankmodell usw.). diff --git a/docs/de/docs/advanced/response-cookies.md b/docs/de/docs/advanced/response-cookies.md index 02fe99c26a..87e636cfaf 100644 --- a/docs/de/docs/advanced/response-cookies.md +++ b/docs/de/docs/advanced/response-cookies.md @@ -6,7 +6,7 @@ Sie können einen Parameter vom Typ `Response` in Ihrer *Pfadoperation-Funktion* Und dann können Sie Cookies in diesem *vorübergehenden* Response-Objekt setzen. -{* ../../docs_src/response_cookies/tutorial002.py hl[1, 8:9] *} +{* ../../docs_src/response_cookies/tutorial002_py39.py hl[1, 8:9] *} Anschließend können Sie wie gewohnt jedes gewünschte Objekt zurückgeben (ein `dict`, ein Datenbankmodell, usw.). @@ -24,7 +24,7 @@ Dazu können Sie eine Response erstellen, wie unter [Eine Response direkt zurüc Setzen Sie dann Cookies darin und geben Sie sie dann zurück: -{* ../../docs_src/response_cookies/tutorial001.py hl[10:12] *} +{* ../../docs_src/response_cookies/tutorial001_py39.py hl[10:12] *} /// tip | Tipp diff --git a/docs/de/docs/advanced/response-directly.md b/docs/de/docs/advanced/response-directly.md index 06ec2c32ed..0a28a6d0e2 100644 --- a/docs/de/docs/advanced/response-directly.md +++ b/docs/de/docs/advanced/response-directly.md @@ -54,7 +54,7 @@ Nehmen wir an, Sie möchten eine Response-Objekt festlegen. -{* ../../docs_src/response_headers/tutorial002.py hl[1, 7:8] *} +{* ../../docs_src/response_headers/tutorial002_py39.py hl[1, 7:8] *} Anschließend können Sie wie gewohnt jedes gewünschte Objekt zurückgeben (ein `dict`, ein Datenbankmodell, usw.). @@ -22,7 +22,7 @@ Sie können auch Header hinzufügen, wenn Sie eine `Response` direkt zurückgebe Erstellen Sie eine Response wie in [Eine Response direkt zurückgeben](response-directly.md){.internal-link target=_blank} beschrieben und übergeben Sie die Header als zusätzlichen Parameter: -{* ../../docs_src/response_headers/tutorial001.py hl[10:12] *} +{* ../../docs_src/response_headers/tutorial001_py39.py hl[10:12] *} /// note | Technische Details diff --git a/docs/de/docs/advanced/settings.md b/docs/de/docs/advanced/settings.md index 03263a28b0..ebacf76f42 100644 --- a/docs/de/docs/advanced/settings.md +++ b/docs/de/docs/advanced/settings.md @@ -62,7 +62,7 @@ Sie können dieselben Validierungs-Funktionen und -Tools verwenden, die Sie für //// tab | Pydantic v2 -{* ../../docs_src/settings/tutorial001.py hl[2,5:8,11] *} +{* ../../docs_src/settings/tutorial001_py39.py hl[2,5:8,11] *} //// @@ -74,7 +74,7 @@ In Pydantic v1 würden Sie `BaseSettings` direkt von `pydantic` statt von `pydan /// -{* ../../docs_src/settings/tutorial001_pv1.py hl[2,5:8,11] *} +{* ../../docs_src/settings/tutorial001_pv1_py39.py hl[2,5:8,11] *} //// @@ -92,7 +92,7 @@ Als Nächstes werden die Daten konvertiert und validiert. Wenn Sie also dieses ` Dann können Sie das neue `settings`-Objekt in Ihrer Anwendung verwenden: -{* ../../docs_src/settings/tutorial001.py hl[18:20] *} +{* ../../docs_src/settings/tutorial001_py39.py hl[18:20] *} ### Den Server ausführen { #run-the-server } @@ -126,11 +126,11 @@ Sie könnten diese Einstellungen in eine andere Moduldatei einfügen, wie Sie in Sie könnten beispielsweise eine Datei `config.py` haben mit: -{* ../../docs_src/settings/app01/config.py *} +{* ../../docs_src/settings/app01_py39/config.py *} Und dann verwenden Sie diese in einer Datei `main.py`: -{* ../../docs_src/settings/app01/main.py hl[3,11:13] *} +{* ../../docs_src/settings/app01_py39/main.py hl[3,11:13] *} /// tip | Tipp diff --git a/docs/de/docs/advanced/sub-applications.md b/docs/de/docs/advanced/sub-applications.md index d634aac23b..081574d0a9 100644 --- a/docs/de/docs/advanced/sub-applications.md +++ b/docs/de/docs/advanced/sub-applications.md @@ -10,7 +10,7 @@ Wenn Sie zwei unabhängige FastAPI-Anwendungen mit deren eigenen unabhängigen O Erstellen Sie zunächst die Hauptanwendung **FastAPI** und deren *Pfadoperationen*: -{* ../../docs_src/sub_applications/tutorial001.py hl[3, 6:8] *} +{* ../../docs_src/sub_applications/tutorial001_py39.py hl[3, 6:8] *} ### Unteranwendung { #sub-application } @@ -18,7 +18,7 @@ Erstellen Sie dann Ihre Unteranwendung und deren *Pfadoperationen*. Diese Unteranwendung ist nur eine weitere Standard-FastAPI-Anwendung, aber diese wird „gemountet“: -{* ../../docs_src/sub_applications/tutorial001.py hl[11, 14:16] *} +{* ../../docs_src/sub_applications/tutorial001_py39.py hl[11, 14:16] *} ### Die Unteranwendung mounten { #mount-the-sub-application } @@ -26,7 +26,7 @@ Mounten Sie in Ihrer Top-Level-Anwendung `app` die Unteranwendung `subapi`. In diesem Fall wird sie im Pfad `/subapi` gemountet: -{* ../../docs_src/sub_applications/tutorial001.py hl[11, 19] *} +{* ../../docs_src/sub_applications/tutorial001_py39.py hl[11, 19] *} ### Die automatische API-Dokumentation testen { #check-the-automatic-api-docs } diff --git a/docs/de/docs/advanced/templates.md b/docs/de/docs/advanced/templates.md index 65c7998b8a..97a45e6126 100644 --- a/docs/de/docs/advanced/templates.md +++ b/docs/de/docs/advanced/templates.md @@ -27,7 +27,7 @@ $ pip install jinja2 * Deklarieren Sie einen `Request`-Parameter in der *Pfadoperation*, welcher ein Template zurückgibt. * Verwenden Sie die von Ihnen erstellten `templates`, um eine `TemplateResponse` zu rendern und zurückzugeben, übergeben Sie den Namen des Templates, das Requestobjekt und ein „Kontext“-Dictionary mit Schlüssel-Wert-Paaren, die innerhalb des Jinja2-Templates verwendet werden sollen. -{* ../../docs_src/templates/tutorial001.py hl[4,11,15:18] *} +{* ../../docs_src/templates/tutorial001_py39.py hl[4,11,15:18] *} /// note | Hinweis diff --git a/docs/de/docs/advanced/testing-events.md b/docs/de/docs/advanced/testing-events.md index 569518c51d..5b12f3f186 100644 --- a/docs/de/docs/advanced/testing-events.md +++ b/docs/de/docs/advanced/testing-events.md @@ -2,11 +2,11 @@ Wenn Sie `lifespan` in Ihren Tests ausführen müssen, können Sie den `TestClient` mit einer `with`-Anweisung verwenden: -{* ../../docs_src/app_testing/tutorial004.py hl[9:15,18,27:28,30:32,41:43] *} +{* ../../docs_src/app_testing/tutorial004_py39.py hl[9:15,18,27:28,30:32,41:43] *} Sie können mehr Details unter [„Lifespan in Tests ausführen in der offiziellen Starlette-Dokumentation.“](https://www.starlette.dev/lifespan/#running-lifespan-in-tests) nachlesen. Für die deprecateten Events `startup` und `shutdown` können Sie den `TestClient` wie folgt verwenden: -{* ../../docs_src/app_testing/tutorial003.py hl[9:12,20:24] *} +{* ../../docs_src/app_testing/tutorial003_py39.py hl[9:12,20:24] *} diff --git a/docs/de/docs/advanced/testing-websockets.md b/docs/de/docs/advanced/testing-websockets.md index f25aa4fd04..9ecca7a4f7 100644 --- a/docs/de/docs/advanced/testing-websockets.md +++ b/docs/de/docs/advanced/testing-websockets.md @@ -4,7 +4,7 @@ Sie können den schon bekannten `TestClient` zum Testen von WebSockets verwenden Dazu verwenden Sie den `TestClient` in einer `with`-Anweisung, eine Verbindung zum WebSocket herstellend: -{* ../../docs_src/app_testing/tutorial002.py hl[27:31] *} +{* ../../docs_src/app_testing/tutorial002_py39.py hl[27:31] *} /// note | Hinweis diff --git a/docs/de/docs/advanced/using-request-directly.md b/docs/de/docs/advanced/using-request-directly.md index 8ec6741d07..36d73b8067 100644 --- a/docs/de/docs/advanced/using-request-directly.md +++ b/docs/de/docs/advanced/using-request-directly.md @@ -29,7 +29,7 @@ Angenommen, Sie möchten auf die IP-Adresse/den Host des Clients in Ihrer *Pfado Dazu müssen Sie direkt auf den Request zugreifen. -{* ../../docs_src/using_request_directly/tutorial001.py hl[1,7:8] *} +{* ../../docs_src/using_request_directly/tutorial001_py39.py hl[1,7:8] *} Durch die Deklaration eines *Pfadoperation-Funktionsparameters*, dessen Typ der `Request` ist, weiß **FastAPI**, dass es den `Request` diesem Parameter übergeben soll. diff --git a/docs/de/docs/advanced/websockets.md b/docs/de/docs/advanced/websockets.md index 5f662770f0..05ae5a4b31 100644 --- a/docs/de/docs/advanced/websockets.md +++ b/docs/de/docs/advanced/websockets.md @@ -38,13 +38,13 @@ In der Produktion hätten Sie eine der oben genannten Optionen. Aber es ist der einfachste Weg, sich auf die Serverseite von WebSockets zu konzentrieren und ein funktionierendes Beispiel zu haben: -{* ../../docs_src/websockets/tutorial001.py hl[2,6:38,41:43] *} +{* ../../docs_src/websockets/tutorial001_py39.py hl[2,6:38,41:43] *} ## Einen `websocket` erstellen { #create-a-websocket } Erstellen Sie in Ihrer **FastAPI**-Anwendung einen `websocket`: -{* ../../docs_src/websockets/tutorial001.py hl[1,46:47] *} +{* ../../docs_src/websockets/tutorial001_py39.py hl[1,46:47] *} /// note | Technische Details @@ -58,7 +58,7 @@ Sie könnten auch `from starlette.websockets import WebSocket` verwenden. In Ihrer WebSocket-Route können Sie Nachrichten `await`en und Nachrichten senden. -{* ../../docs_src/websockets/tutorial001.py hl[48:52] *} +{* ../../docs_src/websockets/tutorial001_py39.py hl[48:52] *} Sie können Binär-, Text- und JSON-Daten empfangen und senden. diff --git a/docs/de/docs/advanced/wsgi.md b/docs/de/docs/advanced/wsgi.md index 1de9739dde..3cd776a6ab 100644 --- a/docs/de/docs/advanced/wsgi.md +++ b/docs/de/docs/advanced/wsgi.md @@ -12,7 +12,7 @@ Wrappen Sie dann die WSGI-Anwendung (z. B. Flask) mit der Middleware. Und dann mounten Sie das auf einem Pfad. -{* ../../docs_src/wsgi/tutorial001.py hl[2:3,3] *} +{* ../../docs_src/wsgi/tutorial001_py39.py hl[2:3,3] *} ## Es testen { #check-it } diff --git a/docs/de/docs/how-to/conditional-openapi.md b/docs/de/docs/how-to/conditional-openapi.md index f6a2fad3bc..6e665cc4c0 100644 --- a/docs/de/docs/how-to/conditional-openapi.md +++ b/docs/de/docs/how-to/conditional-openapi.md @@ -29,7 +29,7 @@ Sie können problemlos dieselben Pydantic-Einstellungen verwenden, um Ihre gener Zum Beispiel: -{* ../../docs_src/conditional_openapi/tutorial001.py hl[6,11] *} +{* ../../docs_src/conditional_openapi/tutorial001_py39.py hl[6,11] *} Hier deklarieren wir die Einstellung `openapi_url` mit dem gleichen Defaultwert `"/openapi.json"`. diff --git a/docs/de/docs/how-to/configure-swagger-ui.md b/docs/de/docs/how-to/configure-swagger-ui.md index 3616f03ac4..1c3f5c0c5a 100644 --- a/docs/de/docs/how-to/configure-swagger-ui.md +++ b/docs/de/docs/how-to/configure-swagger-ui.md @@ -18,7 +18,7 @@ Ohne Änderung der Einstellungen ist die Syntaxhervorhebung standardmäßig akti Sie können sie jedoch deaktivieren, indem Sie `syntaxHighlight` auf `False` setzen: -{* ../../docs_src/configure_swagger_ui/tutorial001.py hl[3] *} +{* ../../docs_src/configure_swagger_ui/tutorial001_py39.py hl[3] *} ... und dann zeigt die Swagger-Oberfläche die Syntaxhervorhebung nicht mehr an: @@ -28,7 +28,7 @@ Sie können sie jedoch deaktivieren, indem Sie `syntaxHighlight` auf `False` set Auf die gleiche Weise könnten Sie das Theme der Syntaxhervorhebung mit dem Schlüssel `"syntaxHighlight.theme"` festlegen (beachten Sie, dass er einen Punkt in der Mitte hat): -{* ../../docs_src/configure_swagger_ui/tutorial002.py hl[3] *} +{* ../../docs_src/configure_swagger_ui/tutorial002_py39.py hl[3] *} Obige Konfiguration würde das Theme für die Farbe der Syntaxhervorhebung ändern: @@ -46,7 +46,7 @@ Sie können jede davon überschreiben, indem Sie im Argument `swagger_ui_paramet Um beispielsweise `deepLinking` zu deaktivieren, könnten Sie folgende Einstellungen an `swagger_ui_parameters` übergeben: -{* ../../docs_src/configure_swagger_ui/tutorial003.py hl[3] *} +{* ../../docs_src/configure_swagger_ui/tutorial003_py39.py hl[3] *} ## Andere Parameter der Swagger-Oberfläche { #other-swagger-ui-parameters } diff --git a/docs/de/docs/how-to/custom-docs-ui-assets.md b/docs/de/docs/how-to/custom-docs-ui-assets.md index 6b8b1a1767..6b1d654adf 100644 --- a/docs/de/docs/how-to/custom-docs-ui-assets.md +++ b/docs/de/docs/how-to/custom-docs-ui-assets.md @@ -18,7 +18,7 @@ Der erste Schritt besteht darin, die automatischen Dokumentationen zu deaktivier Um diese zu deaktivieren, setzen Sie deren URLs beim Erstellen Ihrer `FastAPI`-App auf `None`: -{* ../../docs_src/custom_docs_ui/tutorial001.py hl[8] *} +{* ../../docs_src/custom_docs_ui/tutorial001_py39.py hl[8] *} ### Die benutzerdefinierten Dokumentationen hinzufügen { #include-the-custom-docs } @@ -34,7 +34,7 @@ Sie können die internen Funktionen von FastAPI wiederverwenden, um die HTML-Sei Und ähnlich für ReDoc ... -{* ../../docs_src/custom_docs_ui/tutorial001.py hl[2:6,11:19,22:24,27:33] *} +{* ../../docs_src/custom_docs_ui/tutorial001_py39.py hl[2:6,11:19,22:24,27:33] *} /// tip | Tipp @@ -50,7 +50,7 @@ Swagger UI erledigt das hinter den Kulissen für Sie, benötigt aber diesen „U Um nun testen zu können, ob alles funktioniert, erstellen Sie eine *Pfadoperation*: -{* ../../docs_src/custom_docs_ui/tutorial001.py hl[36:38] *} +{* ../../docs_src/custom_docs_ui/tutorial001_py39.py hl[36:38] *} ### Es testen { #test-it } @@ -118,7 +118,7 @@ Danach könnte Ihre Dateistruktur wie folgt aussehen: * Importieren Sie `StaticFiles`. * „Mounten“ Sie eine `StaticFiles()`-Instanz in einem bestimmten Pfad. -{* ../../docs_src/custom_docs_ui/tutorial002.py hl[7,11] *} +{* ../../docs_src/custom_docs_ui/tutorial002_py39.py hl[7,11] *} ### Die statischen Dateien testen { #test-the-static-files } @@ -144,7 +144,7 @@ Wie bei der Verwendung eines benutzerdefinierten CDN besteht der erste Schritt d Um sie zu deaktivieren, setzen Sie deren URLs beim Erstellen Ihrer `FastAPI`-App auf `None`: -{* ../../docs_src/custom_docs_ui/tutorial002.py hl[9] *} +{* ../../docs_src/custom_docs_ui/tutorial002_py39.py hl[9] *} ### Die benutzerdefinierten Dokumentationen für statische Dateien hinzufügen { #include-the-custom-docs-for-static-files } @@ -160,7 +160,7 @@ Auch hier können Sie die internen Funktionen von FastAPI wiederverwenden, um di Und ähnlich für ReDoc ... -{* ../../docs_src/custom_docs_ui/tutorial002.py hl[2:6,14:22,25:27,30:36] *} +{* ../../docs_src/custom_docs_ui/tutorial002_py39.py hl[2:6,14:22,25:27,30:36] *} /// tip | Tipp @@ -176,7 +176,7 @@ Swagger UI erledigt das hinter den Kulissen für Sie, benötigt aber diesen „U Um nun testen zu können, ob alles funktioniert, erstellen Sie eine *Pfadoperation*: -{* ../../docs_src/custom_docs_ui/tutorial002.py hl[39:41] *} +{* ../../docs_src/custom_docs_ui/tutorial002_py39.py hl[39:41] *} ### Benutzeroberfläche mit statischen Dateien testen { #test-static-files-ui } diff --git a/docs/de/docs/how-to/extending-openapi.md b/docs/de/docs/how-to/extending-openapi.md index 146ee098bc..c07ed2aa08 100644 --- a/docs/de/docs/how-to/extending-openapi.md +++ b/docs/de/docs/how-to/extending-openapi.md @@ -43,19 +43,19 @@ Fügen wir beispielsweise Requests verwendet. -{* ../../docs_src/extending_openapi/tutorial001.py hl[13:14,25:26] *} +{* ../../docs_src/extending_openapi/tutorial001_py39.py hl[13:14,25:26] *} ### Die Methode überschreiben { #override-the-method } Jetzt können Sie die Methode `.openapi()` durch Ihre neue Funktion ersetzen. -{* ../../docs_src/extending_openapi/tutorial001.py hl[29] *} +{* ../../docs_src/extending_openapi/tutorial001_py39.py hl[29] *} ### Es testen { #check-it } diff --git a/docs/de/docs/how-to/graphql.md b/docs/de/docs/how-to/graphql.md index d2958dcd9e..0583faf4a3 100644 --- a/docs/de/docs/how-to/graphql.md +++ b/docs/de/docs/how-to/graphql.md @@ -35,7 +35,7 @@ Abhängig von Ihrem Anwendungsfall könnten Sie eine andere Bibliothek vorziehen Hier ist eine kleine Vorschau, wie Sie Strawberry mit FastAPI integrieren können: -{* ../../docs_src/graphql/tutorial001.py hl[3,22,25] *} +{* ../../docs_src/graphql/tutorial001_py39.py hl[3,22,25] *} Weitere Informationen zu Strawberry finden Sie in der Strawberry-Dokumentation. diff --git a/docs/de/docs/project-generation.md b/docs/de/docs/project-generation.md index 290f605b38..62702d8529 100644 --- a/docs/de/docs/project-generation.md +++ b/docs/de/docs/project-generation.md @@ -13,7 +13,7 @@ GitHub-Repository: Verkettet sie mit einem Leerzeichen in der Mitte. +* Verkettet sie mit einem Leerzeichen in der Mitte. -{* ../../docs_src/python_types/tutorial001.py hl[2] *} +{* ../../docs_src/python_types/tutorial001_py39.py hl[2] *} ### Es bearbeiten { #edit-it } @@ -78,7 +78,7 @@ Das war's. Das sind die „Typhinweise“: -{* ../../docs_src/python_types/tutorial002.py hl[1] *} +{* ../../docs_src/python_types/tutorial002_py39.py hl[1] *} Das ist nicht das gleiche wie das Deklarieren von Defaultwerten, wie es hier der Fall ist: @@ -106,7 +106,7 @@ Hier können Sie durch die Optionen blättern, bis Sie diejenige finden, bei der Sehen Sie sich diese Funktion an, sie hat bereits Typhinweise: -{* ../../docs_src/python_types/tutorial003.py hl[1] *} +{* ../../docs_src/python_types/tutorial003_py39.py hl[1] *} Da der Editor die Typen der Variablen kennt, erhalten Sie nicht nur Code-Vervollständigung, sondern auch eine Fehlerprüfung: @@ -114,7 +114,7 @@ Da der Editor die Typen der Variablen kennt, erhalten Sie nicht nur Code-Vervoll Jetzt, da Sie wissen, dass Sie das reparieren müssen, konvertieren Sie `age` mittels `str(age)` in einen String: -{* ../../docs_src/python_types/tutorial004.py hl[2] *} +{* ../../docs_src/python_types/tutorial004_py39.py hl[2] *} ## Deklarieren von Typen { #declaring-types } @@ -133,7 +133,7 @@ Zum Beispiel diese: * `bool` * `bytes` -{* ../../docs_src/python_types/tutorial005.py hl[1] *} +{* ../../docs_src/python_types/tutorial005_py39.py hl[1] *} ### Generische Typen mit Typ-Parametern { #generic-types-with-type-parameters } @@ -161,56 +161,24 @@ Wenn Sie über die **neueste Version von Python** verfügen, verwenden Sie die B Definieren wir zum Beispiel eine Variable, die eine `list` von `str` – eine Liste von Strings – sein soll. -//// tab | Python 3.9+ - Deklarieren Sie die Variable mit der gleichen Doppelpunkt-Syntax (`:`). Als Typ nehmen Sie `list`. Da die Liste ein Typ ist, welcher innere Typen enthält, werden diese von eckigen Klammern umfasst: -```Python hl_lines="1" -{!> ../../docs_src/python_types/tutorial006_py39.py!} -``` - -//// - -//// tab | Python 3.8+ - -Von `typing` importieren Sie `List` (mit Großbuchstaben `L`): - -```Python hl_lines="1" -{!> ../../docs_src/python_types/tutorial006.py!} -``` - -Deklarieren Sie die Variable mit der gleichen Doppelpunkt-Syntax (`:`). - -Als Typ nehmen Sie das `List`, das Sie von `typing` importiert haben. - -Da die Liste ein Typ ist, welcher innere Typen enthält, werden diese von eckigen Klammern umfasst: - -```Python hl_lines="4" -{!> ../../docs_src/python_types/tutorial006.py!} -``` - -//// +{* ../../docs_src/python_types/tutorial006_py39.py hl[1] *} /// info | Info Die inneren Typen in den eckigen Klammern werden als „Typ-Parameter“ bezeichnet. -In diesem Fall ist `str` der Typ-Parameter, der an `List` übergeben wird (oder `list` in Python 3.9 und darüber). +In diesem Fall ist `str` der Typ-Parameter, der an `list` übergeben wird. /// Das bedeutet: Die Variable `items` ist eine Liste – `list` – und jedes der Elemente in dieser Liste ist ein String – `str`. -/// tip | Tipp - -Wenn Sie Python 3.9 oder höher verwenden, müssen Sie `List` nicht von `typing` importieren, Sie können stattdessen den regulären `list`-Typ verwenden. - -/// - Auf diese Weise kann Ihr Editor Sie auch bei der Bearbeitung von Einträgen aus der Liste unterstützen: @@ -225,21 +193,7 @@ Und trotzdem weiß der Editor, dass es sich um ein `str` handelt, und bietet ent Das Gleiche gilt für die Deklaration eines Tupels – `tuple` – und einer Menge – `set`: -//// tab | Python 3.9+ - -```Python hl_lines="1" -{!> ../../docs_src/python_types/tutorial007_py39.py!} -``` - -//// - -//// tab | Python 3.8+ - -```Python hl_lines="1 4" -{!> ../../docs_src/python_types/tutorial007.py!} -``` - -//// +{* ../../docs_src/python_types/tutorial007_py39.py hl[1] *} Das bedeutet: @@ -254,21 +208,7 @@ Der erste Typ-Parameter ist für die Schlüssel des `dict`. Der zweite Typ-Parameter ist für die Werte des `dict`: -//// tab | Python 3.9+ - -```Python hl_lines="1" -{!> ../../docs_src/python_types/tutorial008_py39.py!} -``` - -//// - -//// tab | Python 3.8+ - -```Python hl_lines="1 4" -{!> ../../docs_src/python_types/tutorial008.py!} -``` - -//// +{* ../../docs_src/python_types/tutorial008_py39.py hl[1] *} Das bedeutet: @@ -282,7 +222,7 @@ Sie können deklarieren, dass eine Variable einer von **verschiedenen Typen** se In Python 3.6 und höher (inklusive Python 3.10) können Sie den `Union`-Typ von `typing` verwenden und die möglichen Typen innerhalb der eckigen Klammern auflisten. -In Python 3.10 gibt es zusätzlich eine **neue Syntax**, die es erlaubt, die möglichen Typen getrennt von einem vertikalen Balken (`|`) aufzulisten. +In Python 3.10 gibt es zusätzlich eine **neue Syntax**, die es erlaubt, die möglichen Typen getrennt von einem vertikalen Balken (`|`) aufzulisten. //// tab | Python 3.10+ @@ -292,10 +232,10 @@ In Python 3.10 gibt es zusätzlich eine **neue Syntax**, die es erlaubt, die mö //// -//// tab | Python 3.8+ +//// tab | Python 3.9+ ```Python hl_lines="1 4" -{!> ../../docs_src/python_types/tutorial008b.py!} +{!> ../../docs_src/python_types/tutorial008b_py39.py!} ``` //// @@ -309,7 +249,7 @@ Sie können deklarieren, dass ein Wert ein `str`, aber vielleicht auch `None` se In Python 3.6 und darüber (inklusive Python 3.10) können Sie das deklarieren, indem Sie `Optional` vom `typing` Modul importieren und verwenden. ```Python hl_lines="1 4" -{!../../docs_src/python_types/tutorial009.py!} +{!../../docs_src/python_types/tutorial009_py39.py!} ``` Wenn Sie `Optional[str]` anstelle von nur `str` verwenden, wird Ihr Editor Ihnen dabei helfen, Fehler zu erkennen, bei denen Sie annehmen könnten, dass ein Wert immer eine String (`str`) ist, obwohl er auch `None` sein könnte. @@ -326,18 +266,18 @@ Das bedeutet auch, dass Sie in Python 3.10 `Something | None` verwenden können: //// -//// tab | Python 3.8+ +//// tab | Python 3.9+ ```Python hl_lines="1 4" -{!> ../../docs_src/python_types/tutorial009.py!} +{!> ../../docs_src/python_types/tutorial009_py39.py!} ``` //// -//// tab | Python 3.8+ Alternative +//// tab | Python 3.9+ Alternative ```Python hl_lines="1 4" -{!> ../../docs_src/python_types/tutorial009b.py!} +{!> ../../docs_src/python_types/tutorial009b_py39.py!} ``` //// @@ -353,11 +293,11 @@ Beide sind äquivalent und im Hintergrund dasselbe, aber ich empfehle `Union` st Ich denke, `Union[SomeType, None]` ist expliziter bezüglich seiner Bedeutung. -Es geht nur um Wörter und Namen. Aber diese Worte können beeinflussen, wie Sie und Ihre Teamkollegen über den Code denken. +Es geht nur um Worte und Namen. Aber diese Worte können beeinflussen, wie Sie und Ihre Teamkollegen über den Code denken. Nehmen wir zum Beispiel diese Funktion: -{* ../../docs_src/python_types/tutorial009c.py hl[1,4] *} +{* ../../docs_src/python_types/tutorial009c_py39.py hl[1,4] *} Der Parameter `name` ist definiert als `Optional[str]`, aber er ist **nicht optional**, Sie können die Funktion nicht ohne diesen Parameter aufrufen: @@ -390,13 +330,13 @@ Sie können die eingebauten Typen als Generics verwenden (mit eckigen Klammern u * `set` * `dict` -Verwenden Sie für den Rest, wie unter Python 3.8, das `typing`-Modul: +Und ebenso wie bei früheren Python-Versionen, aus dem `typing`-Modul: * `Union` -* `Optional` (so wie unter Python 3.8) +* `Optional` * ... und andere. -In Python 3.10 können Sie als Alternative zu den Generics `Union` und `Optional` den vertikalen Balken (`|`) verwenden, um Vereinigungen von Typen zu deklarieren, das ist besser und einfacher. +In Python 3.10 können Sie als Alternative zu den Generics `Union` und `Optional` den vertikalen Balken (`|`) verwenden, um Vereinigungen von Typen zu deklarieren, das ist besser und einfacher. //// @@ -409,7 +349,7 @@ Sie können die eingebauten Typen als Generics verwenden (mit eckigen Klammern u * `set` * `dict` -Verwenden Sie für den Rest, wie unter Python 3.8, das `typing`-Modul: +Und Generics aus dem `typing`-Modul: * `Union` * `Optional` @@ -417,29 +357,17 @@ Verwenden Sie für den Rest, wie unter Python 3.8, das `typing`-Modul: //// -//// tab | Python 3.8+ - -* `List` -* `Tuple` -* `Set` -* `Dict` -* `Union` -* `Optional` -* ... und andere. - -//// - ### Klassen als Typen { #classes-as-types } Sie können auch eine Klasse als Typ einer Variablen deklarieren. Nehmen wir an, Sie haben eine Klasse `Person`, mit einem Namen: -{* ../../docs_src/python_types/tutorial010.py hl[1:3] *} +{* ../../docs_src/python_types/tutorial010_py39.py hl[1:3] *} Dann können Sie eine Variable vom Typ `Person` deklarieren: -{* ../../docs_src/python_types/tutorial010.py hl[6] *} +{* ../../docs_src/python_types/tutorial010_py39.py hl[6] *} Und wiederum bekommen Sie die volle Editor-Unterstützung: @@ -463,29 +391,7 @@ Und Sie erhalten volle Editor-Unterstützung für dieses Objekt. Ein Beispiel aus der offiziellen Pydantic Dokumentation: -//// tab | Python 3.10+ - -```Python -{!> ../../docs_src/python_types/tutorial011_py310.py!} -``` - -//// - -//// tab | Python 3.9+ - -```Python -{!> ../../docs_src/python_types/tutorial011_py39.py!} -``` - -//// - -//// tab | Python 3.8+ - -```Python -{!> ../../docs_src/python_types/tutorial011.py!} -``` - -//// +{* ../../docs_src/python_types/tutorial011_py310.py *} /// info | Info @@ -507,27 +413,9 @@ Pydantic verhält sich speziell, wenn Sie `Optional` oder `Union[Something, None Python bietet auch die Möglichkeit, **zusätzliche Metadaten** in Typhinweisen unterzubringen, mittels `Annotated`. -//// tab | Python 3.9+ +Seit Python 3.9 ist `Annotated` ein Teil der Standardbibliothek, Sie können es von `typing` importieren. -In Python 3.9 ist `Annotated` ein Teil der Standardbibliothek, Sie können es von `typing` importieren. - -```Python hl_lines="1 4" -{!> ../../docs_src/python_types/tutorial013_py39.py!} -``` - -//// - -//// tab | Python 3.8+ - -In Versionen niedriger als Python 3.9 importieren Sie `Annotated` von `typing_extensions`. - -Es wird bereits mit **FastAPI** installiert sein. - -```Python hl_lines="1 4" -{!> ../../docs_src/python_types/tutorial013.py!} -``` - -//// +{* ../../docs_src/python_types/tutorial013_py39.py hl[1,4] *} Python selbst macht nichts mit `Annotated`. Für Editoren und andere Tools ist der Typ immer noch `str`. diff --git a/docs/de/docs/tutorial/background-tasks.md b/docs/de/docs/tutorial/background-tasks.md index 2c381ccfac..1d34430dc6 100644 --- a/docs/de/docs/tutorial/background-tasks.md +++ b/docs/de/docs/tutorial/background-tasks.md @@ -15,7 +15,7 @@ Hierzu zählen beispielsweise: Importieren Sie zunächst `BackgroundTasks` und definieren Sie einen Parameter in Ihrer *Pfadoperation-Funktion* mit der Typdeklaration `BackgroundTasks`: -{* ../../docs_src/background_tasks/tutorial001.py hl[1,13] *} +{* ../../docs_src/background_tasks/tutorial001_py39.py hl[1,13] *} **FastAPI** erstellt für Sie das Objekt vom Typ `BackgroundTasks` und übergibt es als diesen Parameter. @@ -31,13 +31,13 @@ In diesem Fall schreibt die Taskfunktion in eine Datei (den Versand einer E-Mail Und da der Schreibvorgang nicht `async` und `await` verwendet, definieren wir die Funktion mit normalem `def`: -{* ../../docs_src/background_tasks/tutorial001.py hl[6:9] *} +{* ../../docs_src/background_tasks/tutorial001_py39.py hl[6:9] *} ## Den Hintergrundtask hinzufügen { #add-the-background-task } Übergeben Sie innerhalb Ihrer *Pfadoperation-Funktion* Ihre Taskfunktion mit der Methode `.add_task()` an das *Hintergrundtasks*-Objekt: -{* ../../docs_src/background_tasks/tutorial001.py hl[14] *} +{* ../../docs_src/background_tasks/tutorial001_py39.py hl[14] *} `.add_task()` erhält als Argumente: diff --git a/docs/de/docs/tutorial/body-nested-models.md b/docs/de/docs/tutorial/body-nested-models.md index 324d31928d..65a5d7c1de 100644 --- a/docs/de/docs/tutorial/body-nested-models.md +++ b/docs/de/docs/tutorial/body-nested-models.md @@ -14,35 +14,14 @@ Das bewirkt, dass `tags` eine Liste ist, wenngleich es nichts über den Typ der Aber Python erlaubt es, Listen mit inneren Typen, auch „Typ-Parameter“ genannt, zu deklarieren. -### `List` von `typing` importieren { #import-typings-list } - -In Python 3.9 oder darüber können Sie einfach `list` verwenden, um diese Typannotationen zu deklarieren, wie wir unten sehen werden. 💡 - -In Python-Versionen vor 3.9 (3.6 und darüber), müssen Sie zuerst `List` von Pythons Standardmodul `typing` importieren. - -{* ../../docs_src/body_nested_models/tutorial002.py hl[1] *} - ### Eine `list` mit einem Typ-Parameter deklarieren { #declare-a-list-with-a-type-parameter } -Um Typen wie `list`, `dict`, `tuple` mit inneren Typ-Parametern (inneren Typen) zu deklarieren: - -* Wenn Sie eine Python-Version kleiner als 3.9 verwenden, importieren Sie das Äquivalent zum entsprechenden Typ vom `typing`-Modul -* Überreichen Sie den/die inneren Typ(en) von eckigen Klammern umschlossen, `[` und `]`, als „Typ-Parameter“ - -In Python 3.9 wäre das: +Um Typen zu deklarieren, die Typ-Parameter (innere Typen) haben, wie `list`, `dict`, `tuple`, übergeben Sie den/die inneren Typ(en) als „Typ-Parameter“ in eckigen Klammern: `[` und `]` ```Python my_list: list[str] ``` -Und in Python-Versionen vor 3.9: - -```Python -from typing import List - -my_list: List[str] -``` - Das ist alles Standard-Python-Syntax für Typdeklarationen. Verwenden Sie dieselbe Standardsyntax für Modellattribute mit inneren Typen. @@ -178,12 +157,6 @@ Beachten Sie, wie `Offer` eine Liste von `Item`s hat, die ihrerseits eine option Wenn das äußerste Element des JSON-Bodys, das Sie erwarten, ein JSON-`array` (eine Python-`list`) ist, können Sie den Typ im Funktionsparameter deklarieren, mit der gleichen Syntax wie in Pydantic-Modellen: -```Python -images: List[Image] -``` - -oder in Python 3.9 und darüber: - ```Python images: list[Image] ``` diff --git a/docs/de/docs/tutorial/body.md b/docs/de/docs/tutorial/body.md index 1e6382b6f2..0ad95b0386 100644 --- a/docs/de/docs/tutorial/body.md +++ b/docs/de/docs/tutorial/body.md @@ -162,7 +162,7 @@ Die Funktionsparameter werden wie folgt erkannt: FastAPI weiß, dass der Wert von `q` nicht erforderlich ist, aufgrund des definierten Defaultwertes `= None`. -Das `str | None` (Python 3.10+) oder `Union` in `Union[str, None]` (Python 3.8+) wird von FastAPI nicht verwendet, um zu bestimmen, dass der Wert nicht erforderlich ist. FastAPI weiß, dass er nicht erforderlich ist, weil er einen Defaultwert von `= None` hat. +Das `str | None` (Python 3.10+) oder `Union` in `Union[str, None]` (Python 3.9+) wird von FastAPI nicht verwendet, um zu bestimmen, dass der Wert nicht erforderlich ist. FastAPI weiß, dass er nicht erforderlich ist, weil er einen Defaultwert von `= None` hat. Das Hinzufügen der Typannotationen ermöglicht jedoch Ihrem Editor, Ihnen eine bessere Unterstützung zu bieten und Fehler zu erkennen. diff --git a/docs/de/docs/tutorial/cors.md b/docs/de/docs/tutorial/cors.md index 191a7b4ef3..81f0f36051 100644 --- a/docs/de/docs/tutorial/cors.md +++ b/docs/de/docs/tutorial/cors.md @@ -46,7 +46,7 @@ Sie können auch angeben, ob Ihr Backend erlaubt: * Bestimmte HTTP-Methoden (`POST`, `PUT`) oder alle mit der Wildcard `"*"`. * Bestimmte HTTP-Header oder alle mit der Wildcard `"*"`. -{* ../../docs_src/cors/tutorial001.py hl[2,6:11,13:19] *} +{* ../../docs_src/cors/tutorial001_py39.py hl[2,6:11,13:19] *} Die von der `CORSMiddleware`-Implementierung verwendeten Defaultparameter sind standardmäßig restriktiv, daher müssen Sie bestimmte Origins, Methoden oder Header ausdrücklich aktivieren, damit Browser sie in einem Cross-Domain-Kontext verwenden dürfen. diff --git a/docs/de/docs/tutorial/debugging.md b/docs/de/docs/tutorial/debugging.md index 0a31f86536..0d12877c10 100644 --- a/docs/de/docs/tutorial/debugging.md +++ b/docs/de/docs/tutorial/debugging.md @@ -6,7 +6,7 @@ Sie können den Debugger in Ihrem Editor verbinden, zum Beispiel mit Visual Stud Importieren und führen Sie `uvicorn` direkt in Ihrer FastAPI-Anwendung aus: -{* ../../docs_src/debugging/tutorial001.py hl[1,15] *} +{* ../../docs_src/debugging/tutorial001_py39.py hl[1,15] *} ### Über `__name__ == "__main__"` { #about-name-main } diff --git a/docs/de/docs/tutorial/dependencies/classes-as-dependencies.md b/docs/de/docs/tutorial/dependencies/classes-as-dependencies.md index 3d4493f353..7df0842eb1 100644 --- a/docs/de/docs/tutorial/dependencies/classes-as-dependencies.md +++ b/docs/de/docs/tutorial/dependencies/classes-as-dependencies.md @@ -101,7 +101,7 @@ Jetzt können Sie Ihre Abhängigkeit mithilfe dieser Klasse deklarieren. Beachten Sie, wie wir `CommonQueryParams` im obigen Code zweimal schreiben: -//// tab | Python 3.8+ +//// tab | Python 3.9+ ```Python commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)] @@ -109,7 +109,7 @@ commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)] //// -//// tab | Python 3.8+ nicht annotiert +//// tab | Python 3.9+ nicht annotiert /// tip | Tipp @@ -137,7 +137,7 @@ Aus diesem extrahiert FastAPI die deklarierten Parameter, und dieses ist es, was In diesem Fall hat das erste `CommonQueryParams` in: -//// tab | Python 3.8+ +//// tab | Python 3.9+ ```Python commons: Annotated[CommonQueryParams, ... @@ -145,7 +145,7 @@ commons: Annotated[CommonQueryParams, ... //// -//// tab | Python 3.8+ nicht annotiert +//// tab | Python 3.9+ nicht annotiert /// tip | Tipp @@ -163,7 +163,7 @@ commons: CommonQueryParams ... Sie könnten tatsächlich einfach schreiben: -//// tab | Python 3.8+ +//// tab | Python 3.9+ ```Python commons: Annotated[Any, Depends(CommonQueryParams)] @@ -171,7 +171,7 @@ commons: Annotated[Any, Depends(CommonQueryParams)] //// -//// tab | Python 3.8+ nicht annotiert +//// tab | Python 3.9+ nicht annotiert /// tip | Tipp @@ -197,7 +197,7 @@ Es wird jedoch empfohlen, den Typ zu deklarieren, da Ihr Editor so weiß, was al Aber Sie sehen, dass wir hier etwas Codeduplizierung haben, indem wir `CommonQueryParams` zweimal schreiben: -//// tab | Python 3.8+ +//// tab | Python 3.9+ ```Python commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)] @@ -205,7 +205,7 @@ commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)] //// -//// tab | Python 3.8+ nicht annotiert +//// tab | Python 3.9+ nicht annotiert /// tip | Tipp @@ -225,7 +225,7 @@ In diesem speziellen Fall können Sie Folgendes tun: Anstatt zu schreiben: -//// tab | Python 3.8+ +//// tab | Python 3.9+ ```Python commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)] @@ -233,7 +233,7 @@ commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)] //// -//// tab | Python 3.8+ nicht annotiert +//// tab | Python 3.9+ nicht annotiert /// tip | Tipp @@ -249,7 +249,7 @@ commons: CommonQueryParams = Depends(CommonQueryParams) ... schreiben Sie: -//// tab | Python 3.8+ +//// tab | Python 3.9+ ```Python commons: Annotated[CommonQueryParams, Depends()] @@ -257,7 +257,7 @@ commons: Annotated[CommonQueryParams, Depends()] //// -//// tab | Python 3.8 nicht annotiert +//// tab | Python 3.9+ nicht annotiert /// tip | Tipp diff --git a/docs/de/docs/tutorial/dependencies/dependencies-with-yield.md b/docs/de/docs/tutorial/dependencies/dependencies-with-yield.md index 34db6c6bed..0083e7e7ea 100644 --- a/docs/de/docs/tutorial/dependencies/dependencies-with-yield.md +++ b/docs/de/docs/tutorial/dependencies/dependencies-with-yield.md @@ -29,15 +29,15 @@ Sie könnten damit beispielsweise eine Datenbanksession erstellen und diese nach Nur der Code vor und einschließlich der `yield`-Anweisung wird ausgeführt, bevor eine Response erzeugt wird: -{* ../../docs_src/dependencies/tutorial007.py hl[2:4] *} +{* ../../docs_src/dependencies/tutorial007_py39.py hl[2:4] *} Der ge`yield`ete Wert ist das, was in *Pfadoperationen* und andere Abhängigkeiten eingefügt wird: -{* ../../docs_src/dependencies/tutorial007.py hl[4] *} +{* ../../docs_src/dependencies/tutorial007_py39.py hl[4] *} Der auf die `yield`-Anweisung folgende Code wird nach der Response ausgeführt: -{* ../../docs_src/dependencies/tutorial007.py hl[5:6] *} +{* ../../docs_src/dependencies/tutorial007_py39.py hl[5:6] *} /// tip | Tipp @@ -57,7 +57,7 @@ Sie können also mit `except SomeException` diese bestimmte Exception innerhalb Auf die gleiche Weise können Sie `finally` verwenden, um sicherzustellen, dass die Exit-Schritte ausgeführt werden, unabhängig davon, ob eine Exception geworfen wurde oder nicht. -{* ../../docs_src/dependencies/tutorial007.py hl[3,5] *} +{* ../../docs_src/dependencies/tutorial007_py39.py hl[3,5] *} ## Unterabhängigkeiten mit `yield` { #sub-dependencies-with-yield } @@ -268,7 +268,7 @@ In Python können Sie Kontextmanager erstellen, indem Sie Requests zuständig ist, die an: @@ -320,7 +320,7 @@ Das ist unsere „**Pfadoperation-Funktion**“: * **Operation**: ist `get`. * **Funktion**: ist die Funktion direkt unter dem „Dekorator“ (unter `@app.get("/")`). -{* ../../docs_src/first_steps/tutorial001.py hl[7] *} +{* ../../docs_src/first_steps/tutorial001_py39.py hl[7] *} Dies ist eine Python-Funktion. @@ -332,7 +332,7 @@ In diesem Fall handelt es sich um eine `async`-Funktion. Sie könnten sie auch als normale Funktion anstelle von `async def` definieren: -{* ../../docs_src/first_steps/tutorial003.py hl[7] *} +{* ../../docs_src/first_steps/tutorial003_py39.py hl[7] *} /// note | Hinweis @@ -342,7 +342,7 @@ Wenn Sie den Unterschied nicht kennen, lesen Sie [Async: *„In Eile?“*](../as ### Schritt 5: den Inhalt zurückgeben { #step-5-return-the-content } -{* ../../docs_src/first_steps/tutorial001.py hl[8] *} +{* ../../docs_src/first_steps/tutorial001_py39.py hl[8] *} Sie können ein `dict`, eine `list`, einzelne Werte wie `str`, `int`, usw. zurückgeben. diff --git a/docs/de/docs/tutorial/handling-errors.md b/docs/de/docs/tutorial/handling-errors.md index a39c3db37a..d890b44629 100644 --- a/docs/de/docs/tutorial/handling-errors.md +++ b/docs/de/docs/tutorial/handling-errors.md @@ -25,7 +25,7 @@ Um HTTP-deprecatet kennzeichnen möchten, ohne sie zu entfernen, fügen Sie den Parameter `deprecated` hinzu: -{* ../../docs_src/path_operation_configuration/tutorial006.py hl[16] *} +{* ../../docs_src/path_operation_configuration/tutorial006_py39.py hl[16] *} Sie wird in der interaktiven Dokumentation gut sichtbar als deprecatet markiert werden: diff --git a/docs/de/docs/tutorial/path-params-numeric-validations.md b/docs/de/docs/tutorial/path-params-numeric-validations.md index 5b74749447..8b52e8b42f 100644 --- a/docs/de/docs/tutorial/path-params-numeric-validations.md +++ b/docs/de/docs/tutorial/path-params-numeric-validations.md @@ -54,7 +54,7 @@ Für **FastAPI** spielt es keine Rolle. Es erkennt die Parameter anhand ihrer Na Sie können Ihre Funktion also so deklarieren: -{* ../../docs_src/path_params_numeric_validations/tutorial002.py hl[7] *} +{* ../../docs_src/path_params_numeric_validations/tutorial002_py39.py hl[7] *} Aber bedenken Sie, dass Sie dieses Problem nicht haben, wenn Sie `Annotated` verwenden, da es nicht darauf ankommt, dass Sie keine Funktionsparameter-Defaultwerte für `Query()` oder `Path()` verwenden. @@ -83,7 +83,7 @@ Wenn Sie: Python wird nichts mit diesem `*` machen, aber es wird wissen, dass alle folgenden Parameter als Schlüsselwortargumente (Schlüssel-Wert-Paare) verwendet werden sollen, auch bekannt als kwargs. Selbst wenn diese keinen Defaultwert haben. -{* ../../docs_src/path_params_numeric_validations/tutorial003.py hl[7] *} +{* ../../docs_src/path_params_numeric_validations/tutorial003_py39.py hl[7] *} ### Besser mit `Annotated` { #better-with-annotated } diff --git a/docs/de/docs/tutorial/path-params.md b/docs/de/docs/tutorial/path-params.md index 1db288fb87..1de4973155 100644 --- a/docs/de/docs/tutorial/path-params.md +++ b/docs/de/docs/tutorial/path-params.md @@ -2,7 +2,7 @@ Sie können Pfad-„Parameter“ oder -„Variablen“ mit der gleichen Syntax deklarieren, welche in Python-Formatstrings verwendet wird: -{* ../../docs_src/path_params/tutorial001.py hl[6:7] *} +{* ../../docs_src/path_params/tutorial001_py39.py hl[6:7] *} Der Wert des Pfad-Parameters `item_id` wird Ihrer Funktion als das Argument `item_id` übergeben. @@ -16,7 +16,7 @@ Wenn Sie dieses Beispiel ausführen und auf Enumerationen (oder Enums) gibt es in Python seit Version 3.4. - -/// /// tip | Tipp @@ -158,7 +153,7 @@ Falls Sie sich fragen, was „AlexNet“, „ResNet“ und „LeNet“ ist, das Dann erstellen Sie einen *Pfad-Parameter*, der als Typ die gerade erstellte Enum-Klasse hat (`ModelName`): -{* ../../docs_src/path_params/tutorial005.py hl[16] *} +{* ../../docs_src/path_params/tutorial005_py39.py hl[16] *} ### Die API-Dokumentation testen { #check-the-docs } @@ -174,13 +169,13 @@ Der *Pfad-Parameter* wird ein *Query ist die Menge von Schlüssel-Wert-Paaren, die nach dem `?` in einer URL folgen und durch `&`-Zeichen getrennt sind. @@ -127,7 +127,7 @@ Wenn Sie keinen spezifischen Wert haben wollen, sondern der Parameter einfach op Aber wenn Sie wollen, dass ein Query-Parameter erforderlich ist, vergeben Sie einfach keinen Defaultwert: -{* ../../docs_src/query_params/tutorial005.py hl[6:7] *} +{* ../../docs_src/query_params/tutorial005_py39.py hl[6:7] *} Hier ist `needy` ein erforderlicher Query-Parameter vom Typ `str`. diff --git a/docs/de/docs/tutorial/response-model.md b/docs/de/docs/tutorial/response-model.md index 7b77125cb5..4c0205b31f 100644 --- a/docs/de/docs/tutorial/response-model.md +++ b/docs/de/docs/tutorial/response-model.md @@ -183,7 +183,7 @@ Es kann Fälle geben, bei denen Sie etwas zurückgeben, das kein gültiges Pydan Der häufigste Anwendungsfall ist, wenn Sie [eine Response direkt zurückgeben, wie es später im Handbuch für fortgeschrittene Benutzer erläutert wird](../advanced/response-directly.md){.internal-link target=_blank}. -{* ../../docs_src/response_model/tutorial003_02.py hl[8,10:11] *} +{* ../../docs_src/response_model/tutorial003_02_py39.py hl[8,10:11] *} Dieser einfache Anwendungsfall wird automatisch von FastAPI gehandhabt, weil die Annotation des Rückgabetyps die Klasse (oder eine Unterklasse von) `Response` ist. @@ -193,7 +193,7 @@ Und Tools werden auch glücklich sein, weil sowohl `RedirectResponse` als auch ` Sie können auch eine Unterklasse von `Response` in der Typannotation verwenden. -{* ../../docs_src/response_model/tutorial003_03.py hl[8:9] *} +{* ../../docs_src/response_model/tutorial003_03_py39.py hl[8:9] *} Das wird ebenfalls funktionieren, weil `RedirectResponse` eine Unterklasse von `Response` ist, und FastAPI sich um diesen einfachen Anwendungsfall automatisch kümmert. diff --git a/docs/de/docs/tutorial/response-status-code.md b/docs/de/docs/tutorial/response-status-code.md index 928003c3fc..fd17c99336 100644 --- a/docs/de/docs/tutorial/response-status-code.md +++ b/docs/de/docs/tutorial/response-status-code.md @@ -8,7 +8,7 @@ Genauso wie Sie ein Responsemodell angeben können, können Sie auch den HTTP-St * `@app.delete()` * usw. -{* ../../docs_src/response_status_code/tutorial001.py hl[6] *} +{* ../../docs_src/response_status_code/tutorial001_py39.py hl[6] *} /// note | Hinweis @@ -74,7 +74,7 @@ Um mehr über die einzelnen Statuscodes zu erfahren und welcher wofür verwendet Lassen Sie uns das vorherige Beispiel noch einmal anschauen: -{* ../../docs_src/response_status_code/tutorial001.py hl[6] *} +{* ../../docs_src/response_status_code/tutorial001_py39.py hl[6] *} `201` ist der Statuscode für „Created“ („Erzeugt“). @@ -82,7 +82,7 @@ Aber Sie müssen sich nicht merken, was jeder dieser Codes bedeutet. Sie können die Annehmlichkeit von Variablen aus `fastapi.status` nutzen. -{* ../../docs_src/response_status_code/tutorial002.py hl[1,6] *} +{* ../../docs_src/response_status_code/tutorial002_py39.py hl[1,6] *} Diese sind nur eine Annehmlichkeit, sie enthalten dieselbe Zahl, aber so können Sie die Autovervollständigung Ihres Editors verwenden, um sie zu finden: diff --git a/docs/de/docs/tutorial/static-files.md b/docs/de/docs/tutorial/static-files.md index 0c4e7c8abd..9ba2501756 100644 --- a/docs/de/docs/tutorial/static-files.md +++ b/docs/de/docs/tutorial/static-files.md @@ -7,7 +7,7 @@ Mit `StaticFiles` können Sie statische Dateien aus einem Verzeichnis automatisc * Importieren Sie `StaticFiles`. * „Mounten“ Sie eine `StaticFiles()`-Instanz in einem bestimmten Pfad. -{* ../../docs_src/static_files/tutorial001.py hl[2,6] *} +{* ../../docs_src/static_files/tutorial001_py39.py hl[2,6] *} /// note | Technische Details diff --git a/docs/de/docs/tutorial/testing.md b/docs/de/docs/tutorial/testing.md index b18469998d..d889b1e1fb 100644 --- a/docs/de/docs/tutorial/testing.md +++ b/docs/de/docs/tutorial/testing.md @@ -30,7 +30,7 @@ Verwenden Sie das `TestClient`-Objekt auf die gleiche Weise wie `httpx`. Schreiben Sie einfache `assert`-Anweisungen mit den Standard-Python-Ausdrücken, die Sie überprüfen müssen (wiederum, Standard-`pytest`). -{* ../../docs_src/app_testing/tutorial001.py hl[2,12,15:18] *} +{* ../../docs_src/app_testing/tutorial001_py39.py hl[2,12,15:18] *} /// tip | Tipp @@ -76,7 +76,7 @@ Nehmen wir an, Sie haben eine Dateistruktur wie in [Größere Anwendungen](bigge In der Datei `main.py` haben Sie Ihre **FastAPI**-Anwendung: -{* ../../docs_src/app_testing/main.py *} +{* ../../docs_src/app_testing/app_a_py39/main.py *} ### Testdatei { #testing-file } @@ -93,7 +93,7 @@ Dann könnten Sie eine Datei `test_main.py` mit Ihren Tests haben. Sie könnte s Da sich diese Datei im selben Package befindet, können Sie relative Importe verwenden, um das Objekt `app` aus dem `main`-Modul (`main.py`) zu importieren: -{* ../../docs_src/app_testing/test_main.py hl[3] *} +{* ../../docs_src/app_testing/app_a_py39/test_main.py hl[3] *} ... und haben den Code für die Tests wie zuvor. diff --git a/docs/en/docs/advanced/additional-responses.md b/docs/en/docs/advanced/additional-responses.md index cb3a40d13e..bb70753edd 100644 --- a/docs/en/docs/advanced/additional-responses.md +++ b/docs/en/docs/advanced/additional-responses.md @@ -26,7 +26,7 @@ Each of those response `dict`s can have a key `model`, containing a Pydantic mod For example, to declare another response with a status code `404` and a Pydantic model `Message`, you can write: -{* ../../docs_src/additional_responses/tutorial001.py hl[18,22] *} +{* ../../docs_src/additional_responses/tutorial001_py39.py hl[18,22] *} /// note @@ -203,7 +203,7 @@ For example, you can declare a response with a status code `404` that uses a Pyd And a response with a status code `200` that uses your `response_model`, but includes a custom `example`: -{* ../../docs_src/additional_responses/tutorial003.py hl[20:31] *} +{* ../../docs_src/additional_responses/tutorial003_py39.py hl[20:31] *} It will all be combined and included in your OpenAPI, and shown in the API docs: diff --git a/docs/en/docs/advanced/async-tests.md b/docs/en/docs/advanced/async-tests.md index e920e22c3c..65ddc60b2d 100644 --- a/docs/en/docs/advanced/async-tests.md +++ b/docs/en/docs/advanced/async-tests.md @@ -32,11 +32,11 @@ For a simple example, let's consider a file structure similar to the one describ The file `main.py` would have: -{* ../../docs_src/async_tests/main.py *} +{* ../../docs_src/async_tests/app_a_py39/main.py *} The file `test_main.py` would have the tests for `main.py`, it could look like this now: -{* ../../docs_src/async_tests/test_main.py *} +{* ../../docs_src/async_tests/app_a_py39/test_main.py *} ## Run it { #run-it } @@ -56,7 +56,7 @@ $ pytest The marker `@pytest.mark.anyio` tells pytest that this test function should be called asynchronously: -{* ../../docs_src/async_tests/test_main.py hl[7] *} +{* ../../docs_src/async_tests/app_a_py39/test_main.py hl[7] *} /// tip @@ -66,7 +66,7 @@ Note that the test function is now `async def` instead of just `def` as before w Then we can create an `AsyncClient` with the app, and send async requests to it, using `await`. -{* ../../docs_src/async_tests/test_main.py hl[9:12] *} +{* ../../docs_src/async_tests/app_a_py39/test_main.py hl[9:12] *} This is the equivalent to: diff --git a/docs/en/docs/advanced/behind-a-proxy.md b/docs/en/docs/advanced/behind-a-proxy.md index f4dbd45607..4fef02bd1c 100644 --- a/docs/en/docs/advanced/behind-a-proxy.md +++ b/docs/en/docs/advanced/behind-a-proxy.md @@ -44,7 +44,7 @@ $ fastapi run --forwarded-allow-ips="*" For example, let's say you define a *path operation* `/items/`: -{* ../../docs_src/behind_a_proxy/tutorial001_01.py hl[6] *} +{* ../../docs_src/behind_a_proxy/tutorial001_01_py39.py hl[6] *} If the client tries to go to `/items`, by default, it would be redirected to `/items/`. @@ -115,7 +115,7 @@ In this case, the original path `/app` would actually be served at `/api/v1/app` Even though all your code is written assuming there's just `/app`. -{* ../../docs_src/behind_a_proxy/tutorial001.py hl[6] *} +{* ../../docs_src/behind_a_proxy/tutorial001_py39.py hl[6] *} And the proxy would be **"stripping"** the **path prefix** on the fly before transmitting the request to the app server (probably Uvicorn via FastAPI CLI), keeping your application convinced that it is being served at `/app`, so that you don't have to update all your code to include the prefix `/api/v1`. @@ -193,7 +193,7 @@ You can get the current `root_path` used by your application for each request, i Here we are including it in the message just for demonstration purposes. -{* ../../docs_src/behind_a_proxy/tutorial001.py hl[8] *} +{* ../../docs_src/behind_a_proxy/tutorial001_py39.py hl[8] *} Then, if you start Uvicorn with: @@ -220,7 +220,7 @@ The response would be something like: Alternatively, if you don't have a way to provide a command line option like `--root-path` or equivalent, you can set the `root_path` parameter when creating your FastAPI app: -{* ../../docs_src/behind_a_proxy/tutorial002.py hl[3] *} +{* ../../docs_src/behind_a_proxy/tutorial002_py39.py hl[3] *} Passing the `root_path` to `FastAPI` would be the equivalent of passing the `--root-path` command line option to Uvicorn or Hypercorn. @@ -400,7 +400,7 @@ If you pass a custom list of `servers` and there's a `root_path` (because your A For example: -{* ../../docs_src/behind_a_proxy/tutorial003.py hl[4:7] *} +{* ../../docs_src/behind_a_proxy/tutorial003_py39.py hl[4:7] *} Will generate an OpenAPI schema like: @@ -455,7 +455,7 @@ If you don't specify the `servers` parameter and `root_path` is equal to `/`, th If you don't want **FastAPI** to include an automatic server using the `root_path`, you can use the parameter `root_path_in_servers=False`: -{* ../../docs_src/behind_a_proxy/tutorial004.py hl[9] *} +{* ../../docs_src/behind_a_proxy/tutorial004_py39.py hl[9] *} and then it won't include it in the OpenAPI schema. diff --git a/docs/en/docs/advanced/custom-response.md b/docs/en/docs/advanced/custom-response.md index 0f3d8b7017..e53409c39d 100644 --- a/docs/en/docs/advanced/custom-response.md +++ b/docs/en/docs/advanced/custom-response.md @@ -30,7 +30,7 @@ This is because by default, FastAPI will inspect every item inside and make sure But if you are certain that the content that you are returning is **serializable with JSON**, you can pass it directly to the response class and avoid the extra overhead that FastAPI would have by passing your return content through the `jsonable_encoder` before passing it to the response class. -{* ../../docs_src/custom_response/tutorial001b.py hl[2,7] *} +{* ../../docs_src/custom_response/tutorial001b_py39.py hl[2,7] *} /// info @@ -55,7 +55,7 @@ To return a response with HTML directly from **FastAPI**, use `HTMLResponse`. * Import `HTMLResponse`. * Pass `HTMLResponse` as the parameter `response_class` of your *path operation decorator*. -{* ../../docs_src/custom_response/tutorial002.py hl[2,7] *} +{* ../../docs_src/custom_response/tutorial002_py39.py hl[2,7] *} /// info @@ -73,7 +73,7 @@ As seen in [Return a Response directly](response-directly.md){.internal-link tar The same example from above, returning an `HTMLResponse`, could look like: -{* ../../docs_src/custom_response/tutorial003.py hl[2,7,19] *} +{* ../../docs_src/custom_response/tutorial003_py39.py hl[2,7,19] *} /// warning @@ -97,7 +97,7 @@ The `response_class` will then be used only to document the OpenAPI *path operat For example, it could be something like: -{* ../../docs_src/custom_response/tutorial004.py hl[7,21,23] *} +{* ../../docs_src/custom_response/tutorial004_py39.py hl[7,21,23] *} In this example, the function `generate_html_response()` already generates and returns a `Response` instead of returning the HTML in a `str`. @@ -136,7 +136,7 @@ It accepts the following parameters: FastAPI (actually Starlette) will automatically include a Content-Length header. It will also include a Content-Type header, based on the `media_type` and appending a charset for text types. -{* ../../docs_src/response_directly/tutorial002.py hl[1,18] *} +{* ../../docs_src/response_directly/tutorial002_py39.py hl[1,18] *} ### `HTMLResponse` { #htmlresponse } @@ -146,7 +146,7 @@ Takes some text or bytes and returns an HTML response, as you read above. Takes some text or bytes and returns a plain text response. -{* ../../docs_src/custom_response/tutorial005.py hl[2,7,9] *} +{* ../../docs_src/custom_response/tutorial005_py39.py hl[2,7,9] *} ### `JSONResponse` { #jsonresponse } @@ -180,7 +180,7 @@ This requires installing `ujson` for example with `pip install ujson`. /// -{* ../../docs_src/custom_response/tutorial001.py hl[2,7] *} +{* ../../docs_src/custom_response/tutorial001_py39.py hl[2,7] *} /// tip @@ -194,14 +194,14 @@ Returns an HTTP redirect. Uses a 307 status code (Temporary Redirect) by default You can return a `RedirectResponse` directly: -{* ../../docs_src/custom_response/tutorial006.py hl[2,9] *} +{* ../../docs_src/custom_response/tutorial006_py39.py hl[2,9] *} --- Or you can use it in the `response_class` parameter: -{* ../../docs_src/custom_response/tutorial006b.py hl[2,7,9] *} +{* ../../docs_src/custom_response/tutorial006b_py39.py hl[2,7,9] *} If you do that, then you can return the URL directly from your *path operation* function. @@ -211,13 +211,13 @@ In this case, the `status_code` used will be the default one for the `RedirectRe You can also use the `status_code` parameter combined with the `response_class` parameter: -{* ../../docs_src/custom_response/tutorial006c.py hl[2,7,9] *} +{* ../../docs_src/custom_response/tutorial006c_py39.py hl[2,7,9] *} ### `StreamingResponse` { #streamingresponse } Takes an async generator or a normal generator/iterator and streams the response body. -{* ../../docs_src/custom_response/tutorial007.py hl[2,14] *} +{* ../../docs_src/custom_response/tutorial007_py39.py hl[2,14] *} #### Using `StreamingResponse` with file-like objects { #using-streamingresponse-with-file-like-objects } @@ -227,7 +227,7 @@ That way, you don't have to read it all first in memory, and you can pass that g This includes many libraries to interact with cloud storage, video processing, and others. -{* ../../docs_src/custom_response/tutorial008.py hl[2,10:12,14] *} +{* ../../docs_src/custom_response/tutorial008_py39.py hl[2,10:12,14] *} 1. This is the generator function. It's a "generator function" because it contains `yield` statements inside. 2. By using a `with` block, we make sure that the file-like object is closed after the generator function is done. So, after it finishes sending the response. @@ -256,11 +256,11 @@ Takes a different set of arguments to instantiate than the other response types: File responses will include appropriate `Content-Length`, `Last-Modified` and `ETag` headers. -{* ../../docs_src/custom_response/tutorial009.py hl[2,10] *} +{* ../../docs_src/custom_response/tutorial009_py39.py hl[2,10] *} You can also use the `response_class` parameter: -{* ../../docs_src/custom_response/tutorial009b.py hl[2,8,10] *} +{* ../../docs_src/custom_response/tutorial009b_py39.py hl[2,8,10] *} In this case, you can return the file path directly from your *path operation* function. @@ -274,7 +274,7 @@ Let's say you want it to return indented and formatted JSON, so you want to use You could create a `CustomORJSONResponse`. The main thing you have to do is create a `Response.render(content)` method that returns the content as `bytes`: -{* ../../docs_src/custom_response/tutorial009c.py hl[9:14,17] *} +{* ../../docs_src/custom_response/tutorial009c_py39.py hl[9:14,17] *} Now instead of returning: @@ -300,7 +300,7 @@ The parameter that defines this is `default_response_class`. In the example below, **FastAPI** will use `ORJSONResponse` by default, in all *path operations*, instead of `JSONResponse`. -{* ../../docs_src/custom_response/tutorial010.py hl[2,4] *} +{* ../../docs_src/custom_response/tutorial010_py39.py hl[2,4] *} /// tip diff --git a/docs/en/docs/advanced/events.md b/docs/en/docs/advanced/events.md index d9e3cb52e7..9414b7a3f0 100644 --- a/docs/en/docs/advanced/events.md +++ b/docs/en/docs/advanced/events.md @@ -30,7 +30,7 @@ Let's start with an example and then see it in detail. We create an async function `lifespan()` with `yield` like this: -{* ../../docs_src/events/tutorial003.py hl[16,19] *} +{* ../../docs_src/events/tutorial003_py39.py hl[16,19] *} Here we are simulating the expensive *startup* operation of loading the model by putting the (fake) model function in the dictionary with machine learning models before the `yield`. This code will be executed **before** the application **starts taking requests**, during the *startup*. @@ -48,7 +48,7 @@ Maybe you need to start a new version, or you just got tired of running it. 🤷 The first thing to notice, is that we are defining an async function with `yield`. This is very similar to Dependencies with `yield`. -{* ../../docs_src/events/tutorial003.py hl[14:19] *} +{* ../../docs_src/events/tutorial003_py39.py hl[14:19] *} The first part of the function, before the `yield`, will be executed **before** the application starts. @@ -60,7 +60,7 @@ If you check, the function is decorated with an `@asynccontextmanager`. That converts the function into something called an "**async context manager**". -{* ../../docs_src/events/tutorial003.py hl[1,13] *} +{* ../../docs_src/events/tutorial003_py39.py hl[1,13] *} A **context manager** in Python is something that you can use in a `with` statement, for example, `open()` can be used as a context manager: @@ -82,7 +82,7 @@ In our code example above, we don't use it directly, but we pass it to FastAPI f The `lifespan` parameter of the `FastAPI` app takes an **async context manager**, so we can pass our new `lifespan` async context manager to it. -{* ../../docs_src/events/tutorial003.py hl[22] *} +{* ../../docs_src/events/tutorial003_py39.py hl[22] *} ## Alternative Events (deprecated) { #alternative-events-deprecated } @@ -104,7 +104,7 @@ These functions can be declared with `async def` or normal `def`. To add a function that should be run before the application starts, declare it with the event `"startup"`: -{* ../../docs_src/events/tutorial001.py hl[8] *} +{* ../../docs_src/events/tutorial001_py39.py hl[8] *} In this case, the `startup` event handler function will initialize the items "database" (just a `dict`) with some values. @@ -116,7 +116,7 @@ And your application won't start receiving requests until all the `startup` even To add a function that should be run when the application is shutting down, declare it with the event `"shutdown"`: -{* ../../docs_src/events/tutorial002.py hl[6] *} +{* ../../docs_src/events/tutorial002_py39.py hl[6] *} Here, the `shutdown` event handler function will write a text line `"Application shutdown"` to a file `log.txt`. diff --git a/docs/en/docs/advanced/generate-clients.md b/docs/en/docs/advanced/generate-clients.md index 897c308086..2d0c2aa0c9 100644 --- a/docs/en/docs/advanced/generate-clients.md +++ b/docs/en/docs/advanced/generate-clients.md @@ -167,7 +167,7 @@ But for the generated client, we could **modify** the OpenAPI operation IDs righ We could download the OpenAPI JSON to a file `openapi.json` and then we could **remove that prefixed tag** with a script like this: -{* ../../docs_src/generate_clients/tutorial004.py *} +{* ../../docs_src/generate_clients/tutorial004_py39.py *} //// tab | Node.js diff --git a/docs/en/docs/advanced/middleware.md b/docs/en/docs/advanced/middleware.md index 8deb0d917d..765b389329 100644 --- a/docs/en/docs/advanced/middleware.md +++ b/docs/en/docs/advanced/middleware.md @@ -57,13 +57,13 @@ Enforces that all incoming requests must either be `https` or `wss`. Any incoming request to `http` or `ws` will be redirected to the secure scheme instead. -{* ../../docs_src/advanced_middleware/tutorial001.py hl[2,6] *} +{* ../../docs_src/advanced_middleware/tutorial001_py39.py hl[2,6] *} ## `TrustedHostMiddleware` { #trustedhostmiddleware } Enforces that all incoming requests have a correctly set `Host` header, in order to guard against HTTP Host Header attacks. -{* ../../docs_src/advanced_middleware/tutorial002.py hl[2,6:8] *} +{* ../../docs_src/advanced_middleware/tutorial002_py39.py hl[2,6:8] *} The following arguments are supported: @@ -78,7 +78,7 @@ Handles GZip responses for any request that includes `"gzip"` in the `Accept-Enc The middleware will handle both standard and streaming responses. -{* ../../docs_src/advanced_middleware/tutorial003.py hl[2,6] *} +{* ../../docs_src/advanced_middleware/tutorial003_py39.py hl[2,6] *} The following arguments are supported: diff --git a/docs/en/docs/advanced/openapi-webhooks.md b/docs/en/docs/advanced/openapi-webhooks.md index 416cf4b75b..59f060c032 100644 --- a/docs/en/docs/advanced/openapi-webhooks.md +++ b/docs/en/docs/advanced/openapi-webhooks.md @@ -32,7 +32,7 @@ Webhooks are available in OpenAPI 3.1.0 and above, supported by FastAPI `0.99.0` When you create a **FastAPI** application, there is a `webhooks` attribute that you can use to define *webhooks*, the same way you would define *path operations*, for example with `@app.webhooks.post()`. -{* ../../docs_src/openapi_webhooks/tutorial001.py hl[9:13,36:53] *} +{* ../../docs_src/openapi_webhooks/tutorial001_py39.py hl[9:13,36:53] *} The webhooks that you define will end up in the **OpenAPI** schema and the automatic **docs UI**. diff --git a/docs/en/docs/advanced/path-operation-advanced-configuration.md b/docs/en/docs/advanced/path-operation-advanced-configuration.md index 5879bc5c71..01196af79e 100644 --- a/docs/en/docs/advanced/path-operation-advanced-configuration.md +++ b/docs/en/docs/advanced/path-operation-advanced-configuration.md @@ -12,7 +12,7 @@ You can set the OpenAPI `operationId` to be used in your *path operation* with t You would have to make sure that it is unique for each operation. -{* ../../docs_src/path_operation_advanced_configuration/tutorial001.py hl[6] *} +{* ../../docs_src/path_operation_advanced_configuration/tutorial001_py39.py hl[6] *} ### Using the *path operation function* name as the operationId { #using-the-path-operation-function-name-as-the-operationid } @@ -20,7 +20,7 @@ If you want to use your APIs' function names as `operationId`s, you can iterate You should do it after adding all your *path operations*. -{* ../../docs_src/path_operation_advanced_configuration/tutorial002.py hl[2, 12:21, 24] *} +{* ../../docs_src/path_operation_advanced_configuration/tutorial002_py39.py hl[2, 12:21, 24] *} /// tip @@ -40,7 +40,7 @@ Even if they are in different modules (Python files). To exclude a *path operation* from the generated OpenAPI schema (and thus, from the automatic documentation systems), use the parameter `include_in_schema` and set it to `False`: -{* ../../docs_src/path_operation_advanced_configuration/tutorial003.py hl[6] *} +{* ../../docs_src/path_operation_advanced_configuration/tutorial003_py39.py hl[6] *} ## Advanced description from docstring { #advanced-description-from-docstring } @@ -92,7 +92,7 @@ You can extend the OpenAPI schema for a *path operation* using the parameter `op This `openapi_extra` can be helpful, for example, to declare [OpenAPI Extensions](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#specificationExtensions): -{* ../../docs_src/path_operation_advanced_configuration/tutorial005.py hl[6] *} +{* ../../docs_src/path_operation_advanced_configuration/tutorial005_py39.py hl[6] *} If you open the automatic API docs, your extension will show up at the bottom of the specific *path operation*. @@ -139,7 +139,7 @@ For example, you could decide to read and validate the request with your own cod You could do that with `openapi_extra`: -{* ../../docs_src/path_operation_advanced_configuration/tutorial006.py hl[19:36, 39:40] *} +{* ../../docs_src/path_operation_advanced_configuration/tutorial006_py39.py hl[19:36, 39:40] *} In this example, we didn't declare any Pydantic model. In fact, the request body is not even parsed as JSON, it is read directly as `bytes`, and the function `magic_data_reader()` would be in charge of parsing it in some way. diff --git a/docs/en/docs/advanced/response-change-status-code.md b/docs/en/docs/advanced/response-change-status-code.md index 912ed0f1a1..d9708aa627 100644 --- a/docs/en/docs/advanced/response-change-status-code.md +++ b/docs/en/docs/advanced/response-change-status-code.md @@ -20,7 +20,7 @@ You can declare a parameter of type `Response` in your *path operation function* And then you can set the `status_code` in that *temporal* response object. -{* ../../docs_src/response_change_status_code/tutorial001.py hl[1,9,12] *} +{* ../../docs_src/response_change_status_code/tutorial001_py39.py hl[1,9,12] *} And then you can return any object you need, as you normally would (a `dict`, a database model, etc). diff --git a/docs/en/docs/advanced/response-cookies.md b/docs/en/docs/advanced/response-cookies.md index 1f41d84b7c..5b6fab112b 100644 --- a/docs/en/docs/advanced/response-cookies.md +++ b/docs/en/docs/advanced/response-cookies.md @@ -6,7 +6,7 @@ You can declare a parameter of type `Response` in your *path operation function* And then you can set cookies in that *temporal* response object. -{* ../../docs_src/response_cookies/tutorial002.py hl[1, 8:9] *} +{* ../../docs_src/response_cookies/tutorial002_py39.py hl[1, 8:9] *} And then you can return any object you need, as you normally would (a `dict`, a database model, etc). @@ -24,7 +24,7 @@ To do that, you can create a response as described in [Return a Response Directl Then set Cookies in it, and then return it: -{* ../../docs_src/response_cookies/tutorial001.py hl[10:12] *} +{* ../../docs_src/response_cookies/tutorial001_py39.py hl[10:12] *} /// tip diff --git a/docs/en/docs/advanced/response-directly.md b/docs/en/docs/advanced/response-directly.md index 156b4dac7e..4374cb9637 100644 --- a/docs/en/docs/advanced/response-directly.md +++ b/docs/en/docs/advanced/response-directly.md @@ -54,7 +54,7 @@ Let's say that you want to return an Strawberry documentation. diff --git a/docs/en/docs/management-tasks.md b/docs/en/docs/management-tasks.md index 05cd5d27d0..aac4d6fe40 100644 --- a/docs/en/docs/management-tasks.md +++ b/docs/en/docs/management-tasks.md @@ -239,7 +239,7 @@ A PR should have a specific use case that it is solving. * If the PR is for a feature, it should have docs. * Unless it's a feature we want to discourage, like support for a corner case that we don't want users to use. * The docs should include a source example file, not write Python directly in Markdown. -* If the source example(s) file can have different syntax for Python 3.8, 3.9, 3.10, there should be different versions of the file, and they should be shown in tabs in the docs. +* If the source example(s) file can have different syntax for different Python versions, there should be different versions of the file, and they should be shown in tabs in the docs. * There should be tests testing the source example. * Before the PR is applied, the new tests should fail. * After applying the PR, the new tests should pass. diff --git a/docs/en/docs/python-types.md b/docs/en/docs/python-types.md index e4bd2a8749..b685deef29 100644 --- a/docs/en/docs/python-types.md +++ b/docs/en/docs/python-types.md @@ -22,7 +22,7 @@ If you are a Python expert, and you already know everything about type hints, sk Let's start with a simple example: -{* ../../docs_src/python_types/tutorial001.py *} +{* ../../docs_src/python_types/tutorial001_py39.py *} Calling this program outputs: @@ -36,7 +36,7 @@ The function does the following: * Converts the first letter of each one to upper case with `title()`. * Concatenates them with a space in the middle. -{* ../../docs_src/python_types/tutorial001.py hl[2] *} +{* ../../docs_src/python_types/tutorial001_py39.py hl[2] *} ### Edit it { #edit-it } @@ -78,7 +78,7 @@ That's it. Those are the "type hints": -{* ../../docs_src/python_types/tutorial002.py hl[1] *} +{* ../../docs_src/python_types/tutorial002_py39.py hl[1] *} That is not the same as declaring default values like would be with: @@ -106,7 +106,7 @@ With that, you can scroll, seeing the options, until you find the one that "ring Check this function, it already has type hints: -{* ../../docs_src/python_types/tutorial003.py hl[1] *} +{* ../../docs_src/python_types/tutorial003_py39.py hl[1] *} Because the editor knows the types of the variables, you don't only get completion, you also get error checks: @@ -114,7 +114,7 @@ Because the editor knows the types of the variables, you don't only get completi Now you know that you have to fix it, convert `age` to a string with `str(age)`: -{* ../../docs_src/python_types/tutorial004.py hl[2] *} +{* ../../docs_src/python_types/tutorial004_py39.py hl[2] *} ## Declaring types { #declaring-types } @@ -133,7 +133,7 @@ You can use, for example: * `bool` * `bytes` -{* ../../docs_src/python_types/tutorial005.py hl[1] *} +{* ../../docs_src/python_types/tutorial005_py39.py hl[1] *} ### Generic types with type parameters { #generic-types-with-type-parameters } @@ -161,56 +161,24 @@ If you can use the **latest versions of Python**, use the examples for the lates For example, let's define a variable to be a `list` of `str`. -//// tab | Python 3.9+ - Declare the variable, with the same colon (`:`) syntax. As the type, put `list`. As the list is a type that contains some internal types, you put them in square brackets: -```Python hl_lines="1" -{!> ../../docs_src/python_types/tutorial006_py39.py!} -``` - -//// - -//// tab | Python 3.8+ - -From `typing`, import `List` (with a capital `L`): - -```Python hl_lines="1" -{!> ../../docs_src/python_types/tutorial006.py!} -``` - -Declare the variable, with the same colon (`:`) syntax. - -As the type, put the `List` that you imported from `typing`. - -As the list is a type that contains some internal types, you put them in square brackets: - -```Python hl_lines="4" -{!> ../../docs_src/python_types/tutorial006.py!} -``` - -//// +{* ../../docs_src/python_types/tutorial006_py39.py hl[1] *} /// info Those internal types in the square brackets are called "type parameters". -In this case, `str` is the type parameter passed to `List` (or `list` in Python 3.9 and above). +In this case, `str` is the type parameter passed to `list`. /// That means: "the variable `items` is a `list`, and each of the items in this list is a `str`". -/// tip - -If you use Python 3.9 or above, you don't have to import `List` from `typing`, you can use the same regular `list` type instead. - -/// - By doing that, your editor can provide support even while processing items from the list: @@ -225,21 +193,7 @@ And still, the editor knows it is a `str`, and provides support for that. You would do the same to declare `tuple`s and `set`s: -//// tab | Python 3.9+ - -```Python hl_lines="1" -{!> ../../docs_src/python_types/tutorial007_py39.py!} -``` - -//// - -//// tab | Python 3.8+ - -```Python hl_lines="1 4" -{!> ../../docs_src/python_types/tutorial007.py!} -``` - -//// +{* ../../docs_src/python_types/tutorial007_py39.py hl[1] *} This means: @@ -254,21 +208,7 @@ The first type parameter is for the keys of the `dict`. The second type parameter is for the values of the `dict`: -//// tab | Python 3.9+ - -```Python hl_lines="1" -{!> ../../docs_src/python_types/tutorial008_py39.py!} -``` - -//// - -//// tab | Python 3.8+ - -```Python hl_lines="1 4" -{!> ../../docs_src/python_types/tutorial008.py!} -``` - -//// +{* ../../docs_src/python_types/tutorial008_py39.py hl[1] *} This means: @@ -292,10 +232,10 @@ In Python 3.10 there's also a **new syntax** where you can put the possible type //// -//// tab | Python 3.8+ +//// tab | Python 3.9+ ```Python hl_lines="1 4" -{!> ../../docs_src/python_types/tutorial008b.py!} +{!> ../../docs_src/python_types/tutorial008b_py39.py!} ``` //// @@ -309,7 +249,7 @@ You can declare that a value could have a type, like `str`, but that it could al In Python 3.6 and above (including Python 3.10) you can declare it by importing and using `Optional` from the `typing` module. ```Python hl_lines="1 4" -{!../../docs_src/python_types/tutorial009.py!} +{!../../docs_src/python_types/tutorial009_py39.py!} ``` Using `Optional[str]` instead of just `str` will let the editor help you detect errors where you could be assuming that a value is always a `str`, when it could actually be `None` too. @@ -326,18 +266,18 @@ This also means that in Python 3.10, you can use `Something | None`: //// -//// tab | Python 3.8+ +//// tab | Python 3.9+ ```Python hl_lines="1 4" -{!> ../../docs_src/python_types/tutorial009.py!} +{!> ../../docs_src/python_types/tutorial009_py39.py!} ``` //// -//// tab | Python 3.8+ alternative +//// tab | Python 3.9+ alternative ```Python hl_lines="1 4" -{!> ../../docs_src/python_types/tutorial009b.py!} +{!> ../../docs_src/python_types/tutorial009b_py39.py!} ``` //// @@ -357,7 +297,7 @@ It's just about the words and names. But those words can affect how you and your As an example, let's take this function: -{* ../../docs_src/python_types/tutorial009c.py hl[1,4] *} +{* ../../docs_src/python_types/tutorial009c_py39.py hl[1,4] *} The parameter `name` is defined as `Optional[str]`, but it is **not optional**, you cannot call the function without the parameter: @@ -390,10 +330,10 @@ You can use the same builtin types as generics (with square brackets and types i * `set` * `dict` -And the same as with Python 3.8, from the `typing` module: +And the same as with previous Python versions, from the `typing` module: * `Union` -* `Optional` (the same as with Python 3.8) +* `Optional` * ...and others. In Python 3.10, as an alternative to using the generics `Union` and `Optional`, you can use the vertical bar (`|`) to declare unions of types, that's a lot better and simpler. @@ -409,7 +349,7 @@ You can use the same builtin types as generics (with square brackets and types i * `set` * `dict` -And the same as with Python 3.8, from the `typing` module: +And generics from the `typing` module: * `Union` * `Optional` @@ -417,29 +357,17 @@ And the same as with Python 3.8, from the `typing` module: //// -//// tab | Python 3.8+ - -* `List` -* `Tuple` -* `Set` -* `Dict` -* `Union` -* `Optional` -* ...and others. - -//// - ### Classes as types { #classes-as-types } You can also declare a class as the type of a variable. Let's say you have a class `Person`, with a name: -{* ../../docs_src/python_types/tutorial010.py hl[1:3] *} +{* ../../docs_src/python_types/tutorial010_py39.py hl[1:3] *} Then you can declare a variable to be of type `Person`: -{* ../../docs_src/python_types/tutorial010.py hl[6] *} +{* ../../docs_src/python_types/tutorial010_py39.py hl[6] *} And then, again, you get all the editor support: @@ -463,29 +391,7 @@ And you get all the editor support with that resulting object. An example from the official Pydantic docs: -//// tab | Python 3.10+ - -```Python -{!> ../../docs_src/python_types/tutorial011_py310.py!} -``` - -//// - -//// tab | Python 3.9+ - -```Python -{!> ../../docs_src/python_types/tutorial011_py39.py!} -``` - -//// - -//// tab | Python 3.8+ - -```Python -{!> ../../docs_src/python_types/tutorial011.py!} -``` - -//// +{* ../../docs_src/python_types/tutorial011_py310.py *} /// info @@ -507,27 +413,9 @@ Pydantic has a special behavior when you use `Optional` or `Union[Something, Non Python also has a feature that allows putting **additional metadata** in these type hints using `Annotated`. -//// tab | Python 3.9+ +Since Python 3.9, `Annotated` is a part of the standard library, so you can import it from `typing`. -In Python 3.9, `Annotated` is part of the standard library, so you can import it from `typing`. - -```Python hl_lines="1 4" -{!> ../../docs_src/python_types/tutorial013_py39.py!} -``` - -//// - -//// tab | Python 3.8+ - -In versions below Python 3.9, you import `Annotated` from `typing_extensions`. - -It will already be installed with **FastAPI**. - -```Python hl_lines="1 4" -{!> ../../docs_src/python_types/tutorial013.py!} -``` - -//// +{* ../../docs_src/python_types/tutorial013_py39.py hl[1,4] *} Python itself doesn't do anything with this `Annotated`. And for editors and other tools, the type is still `str`. diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index bb72f4001e..ebec6bff66 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -7,8 +7,28 @@ hide: ## Latest Changes +### Internal + +* 👷 Add performance tests with CodSpeed. PR [#14558](https://github.com/fastapi/fastapi/pull/14558) by [@tiangolo](https://github.com/tiangolo). + +## 0.125.0 + +### Breaking Changes + +* 🔧 Drop support for Python 3.8. PR [#14563](https://github.com/fastapi/fastapi/pull/14563) by [@tiangolo](https://github.com/tiangolo). + * This would actually not be a _breaking_ change as no code would really break. Any Python 3.8 installer would just refuse to install the latest version of FastAPI and would only install 0.124.4. Only marking it as a "breaking change" to make it visible. + +### Refactors + +* ♻️ Upgrade internal syntax to Python 3.9+ 🎉. PR [#14564](https://github.com/fastapi/fastapi/pull/14564) by [@tiangolo](https://github.com/tiangolo). + +### Docs + +* ⚰️ Remove Python 3.8 from CI and remove Python 3.8 examples from source docs. PR [#14559](https://github.com/fastapi/fastapi/pull/14559) by [@YuriiMotov](https://github.com/YuriiMotov) and [@tiangolo](https://github.com/tiangolo). + ### Translations +* 🌐 Update translations for pt (add-missing). PR [#14539](https://github.com/fastapi/fastapi/pull/14539) by [@tiangolo](https://github.com/tiangolo). * 🔧 Add LLM prompt file for French, generated from the existing French docs. PR [#14544](https://github.com/fastapi/fastapi/pull/14544) by [@tiangolo](https://github.com/tiangolo). * 🌐 Sync Portuguese docs (pages found with script). PR [#14554](https://github.com/fastapi/fastapi/pull/14554) by [@YuriiMotov](https://github.com/YuriiMotov). * 🌐 Sync Spanish docs (outdated pages found with script). PR [#14553](https://github.com/fastapi/fastapi/pull/14553) by [@YuriiMotov](https://github.com/YuriiMotov). diff --git a/docs/en/docs/tutorial/background-tasks.md b/docs/en/docs/tutorial/background-tasks.md index ab44f89c19..be7ecd5871 100644 --- a/docs/en/docs/tutorial/background-tasks.md +++ b/docs/en/docs/tutorial/background-tasks.md @@ -15,7 +15,7 @@ This includes, for example: First, import `BackgroundTasks` and define a parameter in your *path operation function* with a type declaration of `BackgroundTasks`: -{* ../../docs_src/background_tasks/tutorial001.py hl[1,13] *} +{* ../../docs_src/background_tasks/tutorial001_py39.py hl[1,13] *} **FastAPI** will create the object of type `BackgroundTasks` for you and pass it as that parameter. @@ -31,13 +31,13 @@ In this case, the task function will write to a file (simulating sending an emai And as the write operation doesn't use `async` and `await`, we define the function with normal `def`: -{* ../../docs_src/background_tasks/tutorial001.py hl[6:9] *} +{* ../../docs_src/background_tasks/tutorial001_py39.py hl[6:9] *} ## Add the background task { #add-the-background-task } Inside of your *path operation function*, pass your task function to the *background tasks* object with the method `.add_task()`: -{* ../../docs_src/background_tasks/tutorial001.py hl[14] *} +{* ../../docs_src/background_tasks/tutorial001_py39.py hl[14] *} `.add_task()` receives as arguments: diff --git a/docs/en/docs/tutorial/body-nested-models.md b/docs/en/docs/tutorial/body-nested-models.md index 445235a420..5fd83a8f3c 100644 --- a/docs/en/docs/tutorial/body-nested-models.md +++ b/docs/en/docs/tutorial/body-nested-models.md @@ -14,35 +14,15 @@ This will make `tags` be a list, although it doesn't declare the type of the ele But Python has a specific way to declare lists with internal types, or "type parameters": -### Import typing's `List` { #import-typings-list } - -In Python 3.9 and above you can use the standard `list` to declare these type annotations as we'll see below. 💡 - -But in Python versions before 3.9 (3.6 and above), you first need to import `List` from standard Python's `typing` module: - -{* ../../docs_src/body_nested_models/tutorial002.py hl[1] *} - ### Declare a `list` with a type parameter { #declare-a-list-with-a-type-parameter } -To declare types that have type parameters (internal types), like `list`, `dict`, `tuple`: - -* If you are in a Python version lower than 3.9, import their equivalent version from the `typing` module -* Pass the internal type(s) as "type parameters" using square brackets: `[` and `]` - -In Python 3.9 it would be: +To declare types that have type parameters (internal types), like `list`, `dict`, `tuple`, +pass the internal type(s) as "type parameters" using square brackets: `[` and `]` ```Python my_list: list[str] ``` -In versions of Python before 3.9, it would be: - -```Python -from typing import List - -my_list: List[str] -``` - That's all standard Python syntax for type declarations. Use that same standard syntax for model attributes with internal types. @@ -178,12 +158,6 @@ Notice how `Offer` has a list of `Item`s, which in turn have an optional list of If the top level value of the JSON body you expect is a JSON `array` (a Python `list`), you can declare the type in the parameter of the function, the same as in Pydantic models: -```Python -images: List[Image] -``` - -or in Python 3.9 and above: - ```Python images: list[Image] ``` diff --git a/docs/en/docs/tutorial/body.md b/docs/en/docs/tutorial/body.md index a820802f74..25087b8406 100644 --- a/docs/en/docs/tutorial/body.md +++ b/docs/en/docs/tutorial/body.md @@ -163,7 +163,7 @@ The function parameters will be recognized as follows: FastAPI will know that the value of `q` is not required because of the default value `= None`. -The `str | None` (Python 3.10+) or `Union` in `Union[str, None]` (Python 3.8+) is not used by FastAPI to determine that the value is not required, it will know it's not required because it has a default value of `= None`. +The `str | None` (Python 3.10+) or `Union` in `Union[str, None]` (Python 3.9+) is not used by FastAPI to determine that the value is not required, it will know it's not required because it has a default value of `= None`. But adding the type annotations will allow your editor to give you better support and detect errors. diff --git a/docs/en/docs/tutorial/cors.md b/docs/en/docs/tutorial/cors.md index e3de37b43c..8a3a8eb0a8 100644 --- a/docs/en/docs/tutorial/cors.md +++ b/docs/en/docs/tutorial/cors.md @@ -46,7 +46,7 @@ You can also specify whether your backend allows: * Specific HTTP methods (`POST`, `PUT`) or all of them with the wildcard `"*"`. * Specific HTTP headers or all of them with the wildcard `"*"`. -{* ../../docs_src/cors/tutorial001.py hl[2,6:11,13:19] *} +{* ../../docs_src/cors/tutorial001_py39.py hl[2,6:11,13:19] *} The default parameters used by the `CORSMiddleware` implementation are restrictive by default, so you'll need to explicitly enable particular origins, methods, or headers, in order for browsers to be permitted to use them in a Cross-Domain context. diff --git a/docs/en/docs/tutorial/debugging.md b/docs/en/docs/tutorial/debugging.md index 08b440084e..a2edfe7203 100644 --- a/docs/en/docs/tutorial/debugging.md +++ b/docs/en/docs/tutorial/debugging.md @@ -6,7 +6,7 @@ You can connect the debugger in your editor, for example with Visual Studio Code In your FastAPI application, import and run `uvicorn` directly: -{* ../../docs_src/debugging/tutorial001.py hl[1,15] *} +{* ../../docs_src/debugging/tutorial001_py39.py hl[1,15] *} ### About `__name__ == "__main__"` { #about-name-main } diff --git a/docs/en/docs/tutorial/dependencies/classes-as-dependencies.md b/docs/en/docs/tutorial/dependencies/classes-as-dependencies.md index 686a5632e2..0a6a786b50 100644 --- a/docs/en/docs/tutorial/dependencies/classes-as-dependencies.md +++ b/docs/en/docs/tutorial/dependencies/classes-as-dependencies.md @@ -101,7 +101,7 @@ Now you can declare your dependency using this class. Notice how we write `CommonQueryParams` twice in the above code: -//// tab | Python 3.8+ +//// tab | Python 3.9+ ```Python commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)] @@ -109,7 +109,7 @@ commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)] //// -//// tab | Python 3.8+ non-Annotated +//// tab | Python 3.9+ non-Annotated /// tip @@ -137,7 +137,7 @@ It is from this one that FastAPI will extract the declared parameters and that i In this case, the first `CommonQueryParams`, in: -//// tab | Python 3.8+ +//// tab | Python 3.9+ ```Python commons: Annotated[CommonQueryParams, ... @@ -145,7 +145,7 @@ commons: Annotated[CommonQueryParams, ... //// -//// tab | Python 3.8+ non-Annotated +//// tab | Python 3.9+ non-Annotated /// tip @@ -163,7 +163,7 @@ commons: CommonQueryParams ... You could actually write just: -//// tab | Python 3.8+ +//// tab | Python 3.9+ ```Python commons: Annotated[Any, Depends(CommonQueryParams)] @@ -171,7 +171,7 @@ commons: Annotated[Any, Depends(CommonQueryParams)] //// -//// tab | Python 3.8+ non-Annotated +//// tab | Python 3.9+ non-Annotated /// tip @@ -197,7 +197,7 @@ But declaring the type is encouraged as that way your editor will know what will But you see that we are having some code repetition here, writing `CommonQueryParams` twice: -//// tab | Python 3.8+ +//// tab | Python 3.9+ ```Python commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)] @@ -205,7 +205,7 @@ commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)] //// -//// tab | Python 3.8+ non-Annotated +//// tab | Python 3.9+ non-Annotated /// tip @@ -225,7 +225,7 @@ For those specific cases, you can do the following: Instead of writing: -//// tab | Python 3.8+ +//// tab | Python 3.9+ ```Python commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)] @@ -233,7 +233,7 @@ commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)] //// -//// tab | Python 3.8+ non-Annotated +//// tab | Python 3.9+ non-Annotated /// tip @@ -249,7 +249,7 @@ commons: CommonQueryParams = Depends(CommonQueryParams) ...you write: -//// tab | Python 3.8+ +//// tab | Python 3.9+ ```Python commons: Annotated[CommonQueryParams, Depends()] @@ -257,7 +257,7 @@ commons: Annotated[CommonQueryParams, Depends()] //// -//// tab | Python 3.8 non-Annotated +//// tab | Python 3.9+ non-Annotated /// tip diff --git a/docs/en/docs/tutorial/dependencies/dependencies-with-yield.md b/docs/en/docs/tutorial/dependencies/dependencies-with-yield.md index 494c40efab..d9f3345619 100644 --- a/docs/en/docs/tutorial/dependencies/dependencies-with-yield.md +++ b/docs/en/docs/tutorial/dependencies/dependencies-with-yield.md @@ -29,15 +29,15 @@ For example, you could use this to create a database session and close it after Only the code prior to and including the `yield` statement is executed before creating a response: -{* ../../docs_src/dependencies/tutorial007.py hl[2:4] *} +{* ../../docs_src/dependencies/tutorial007_py39.py hl[2:4] *} The yielded value is what is injected into *path operations* and other dependencies: -{* ../../docs_src/dependencies/tutorial007.py hl[4] *} +{* ../../docs_src/dependencies/tutorial007_py39.py hl[4] *} The code following the `yield` statement is executed after the response: -{* ../../docs_src/dependencies/tutorial007.py hl[5:6] *} +{* ../../docs_src/dependencies/tutorial007_py39.py hl[5:6] *} /// tip @@ -57,7 +57,7 @@ So, you can look for that specific exception inside the dependency with `except In the same way, you can use `finally` to make sure the exit steps are executed, no matter if there was an exception or not. -{* ../../docs_src/dependencies/tutorial007.py hl[3,5] *} +{* ../../docs_src/dependencies/tutorial007_py39.py hl[3,5] *} ## Sub-dependencies with `yield` { #sub-dependencies-with-yield } @@ -269,7 +269,7 @@ In Python, you can create Context Managers by deprecated, but without removing it, pass the parameter `deprecated`: -{* ../../docs_src/path_operation_configuration/tutorial006.py hl[16] *} +{* ../../docs_src/path_operation_configuration/tutorial006_py39.py hl[16] *} It will be clearly marked as deprecated in the interactive docs: diff --git a/docs/en/docs/tutorial/path-params-numeric-validations.md b/docs/en/docs/tutorial/path-params-numeric-validations.md index f7f2d6ceb0..8b1b8a8392 100644 --- a/docs/en/docs/tutorial/path-params-numeric-validations.md +++ b/docs/en/docs/tutorial/path-params-numeric-validations.md @@ -54,7 +54,7 @@ It doesn't matter for **FastAPI**. It will detect the parameters by their names, So, you can declare your function as: -{* ../../docs_src/path_params_numeric_validations/tutorial002.py hl[7] *} +{* ../../docs_src/path_params_numeric_validations/tutorial002_py39.py hl[7] *} But keep in mind that if you use `Annotated`, you won't have this problem, it won't matter as you're not using the function parameter default values for `Query()` or `Path()`. @@ -83,7 +83,7 @@ Pass `*`, as the first parameter of the function. Python won't do anything with that `*`, but it will know that all the following parameters should be called as keyword arguments (key-value pairs), also known as kwargs. Even if they don't have a default value. -{* ../../docs_src/path_params_numeric_validations/tutorial003.py hl[7] *} +{* ../../docs_src/path_params_numeric_validations/tutorial003_py39.py hl[7] *} ### Better with `Annotated` { #better-with-annotated } diff --git a/docs/en/docs/tutorial/path-params.md b/docs/en/docs/tutorial/path-params.md index 457cc2713f..ea4307900c 100644 --- a/docs/en/docs/tutorial/path-params.md +++ b/docs/en/docs/tutorial/path-params.md @@ -2,7 +2,7 @@ You can declare path "parameters" or "variables" with the same syntax used by Python format strings: -{* ../../docs_src/path_params/tutorial001.py hl[6:7] *} +{* ../../docs_src/path_params/tutorial001_py39.py hl[6:7] *} The value of the path parameter `item_id` will be passed to your function as the argument `item_id`. @@ -16,7 +16,7 @@ So, if you run this example and go to Enumerations (or enums) are available in Python since version 3.4. - -/// +{* ../../docs_src/path_params/tutorial005_py39.py hl[1,6:9] *} /// tip @@ -158,7 +152,7 @@ If you are wondering, "AlexNet", "ResNet", and "LeNet" are just names of Machine Then create a *path parameter* with a type annotation using the enum class you created (`ModelName`): -{* ../../docs_src/path_params/tutorial005.py hl[16] *} +{* ../../docs_src/path_params/tutorial005_py39.py hl[16] *} ### Check the docs { #check-the-docs } @@ -174,13 +168,13 @@ The value of the *path parameter* will be an *enumeration member*. You can compare it with the *enumeration member* in your created enum `ModelName`: -{* ../../docs_src/path_params/tutorial005.py hl[17] *} +{* ../../docs_src/path_params/tutorial005_py39.py hl[17] *} #### Get the *enumeration value* { #get-the-enumeration-value } You can get the actual value (a `str` in this case) using `model_name.value`, or in general, `your_enum_member.value`: -{* ../../docs_src/path_params/tutorial005.py hl[20] *} +{* ../../docs_src/path_params/tutorial005_py39.py hl[20] *} /// tip @@ -194,7 +188,7 @@ You can return *enum members* from your *path operation*, even nested in a JSON They will be converted to their corresponding values (strings in this case) before returning them to the client: -{* ../../docs_src/path_params/tutorial005.py hl[18,21,23] *} +{* ../../docs_src/path_params/tutorial005_py39.py hl[18,21,23] *} In your client you will get a JSON response like: @@ -233,7 +227,7 @@ In this case, the name of the parameter is `file_path`, and the last part, `:pat So, you can use it with: -{* ../../docs_src/path_params/tutorial004.py hl[6] *} +{* ../../docs_src/path_params/tutorial004_py39.py hl[6] *} /// tip diff --git a/docs/en/docs/tutorial/query-params-str-validations.md b/docs/en/docs/tutorial/query-params-str-validations.md index adf08a9249..aba87a4484 100644 --- a/docs/en/docs/tutorial/query-params-str-validations.md +++ b/docs/en/docs/tutorial/query-params-str-validations.md @@ -55,7 +55,7 @@ q: str | None = None //// -//// tab | Python 3.8+ +//// tab | Python 3.9+ ```Python q: Union[str, None] = None @@ -73,7 +73,7 @@ q: Annotated[str | None] = None //// -//// tab | Python 3.8+ +//// tab | Python 3.9+ ```Python q: Annotated[Union[str, None]] = None diff --git a/docs/en/docs/tutorial/query-params.md b/docs/en/docs/tutorial/query-params.md index 2323b83c7c..3c9c225fb0 100644 --- a/docs/en/docs/tutorial/query-params.md +++ b/docs/en/docs/tutorial/query-params.md @@ -2,7 +2,7 @@ When you declare other function parameters that are not part of the path parameters, they are automatically interpreted as "query" parameters. -{* ../../docs_src/query_params/tutorial001.py hl[9] *} +{* ../../docs_src/query_params/tutorial001_py39.py hl[9] *} The query is the set of key-value pairs that go after the `?` in a URL, separated by `&` characters. @@ -128,7 +128,7 @@ If you don't want to add a specific value but just make it optional, set the def But when you want to make a query parameter required, you can just not declare any default value: -{* ../../docs_src/query_params/tutorial005.py hl[6:7] *} +{* ../../docs_src/query_params/tutorial005_py39.py hl[6:7] *} Here the query parameter `needy` is a required query parameter of type `str`. diff --git a/docs/en/docs/tutorial/response-model.md b/docs/en/docs/tutorial/response-model.md index 5090dbcdfd..a38c610d4f 100644 --- a/docs/en/docs/tutorial/response-model.md +++ b/docs/en/docs/tutorial/response-model.md @@ -183,7 +183,7 @@ There might be cases where you return something that is not a valid Pydantic fie The most common case would be [returning a Response directly as explained later in the advanced docs](../advanced/response-directly.md){.internal-link target=_blank}. -{* ../../docs_src/response_model/tutorial003_02.py hl[8,10:11] *} +{* ../../docs_src/response_model/tutorial003_02_py39.py hl[8,10:11] *} This simple case is handled automatically by FastAPI because the return type annotation is the class (or a subclass of) `Response`. @@ -193,7 +193,7 @@ And tools will also be happy because both `RedirectResponse` and `JSONResponse` You can also use a subclass of `Response` in the type annotation: -{* ../../docs_src/response_model/tutorial003_03.py hl[8:9] *} +{* ../../docs_src/response_model/tutorial003_03_py39.py hl[8:9] *} This will also work because `RedirectResponse` is a subclass of `Response`, and FastAPI will automatically handle this simple case. diff --git a/docs/en/docs/tutorial/response-status-code.md b/docs/en/docs/tutorial/response-status-code.md index a2d9757b28..6389592486 100644 --- a/docs/en/docs/tutorial/response-status-code.md +++ b/docs/en/docs/tutorial/response-status-code.md @@ -8,7 +8,7 @@ The same way you can specify a response model, you can also declare the HTTP sta * `@app.delete()` * etc. -{* ../../docs_src/response_status_code/tutorial001.py hl[6] *} +{* ../../docs_src/response_status_code/tutorial001_py39.py hl[6] *} /// note @@ -74,7 +74,7 @@ To know more about each status code and which code is for what, check the parse como JSON, se lee directamente como `bytes`, y la función `magic_data_reader()` sería la encargada de parsearlo de alguna manera. diff --git a/docs/es/docs/advanced/response-change-status-code.md b/docs/es/docs/advanced/response-change-status-code.md index 067267750b..940f1dd3ff 100644 --- a/docs/es/docs/advanced/response-change-status-code.md +++ b/docs/es/docs/advanced/response-change-status-code.md @@ -20,7 +20,7 @@ Puedes declarar un parámetro de tipo `Response` en tu *path operation function* Y luego puedes establecer el `status_code` en ese objeto de response *temporal*. -{* ../../docs_src/response_change_status_code/tutorial001.py hl[1,9,12] *} +{* ../../docs_src/response_change_status_code/tutorial001_py39.py hl[1,9,12] *} Y luego puedes devolver cualquier objeto que necesites, como lo harías normalmente (un `dict`, un modelo de base de datos, etc.). diff --git a/docs/es/docs/advanced/response-cookies.md b/docs/es/docs/advanced/response-cookies.md index ce2ff0281d..550a5d97a7 100644 --- a/docs/es/docs/advanced/response-cookies.md +++ b/docs/es/docs/advanced/response-cookies.md @@ -6,7 +6,7 @@ Puedes declarar un parámetro de tipo `Response` en tu *path operation function* Y luego puedes establecer cookies en ese objeto de response *temporal*. -{* ../../docs_src/response_cookies/tutorial002.py hl[1, 8:9] *} +{* ../../docs_src/response_cookies/tutorial002_py39.py hl[1, 8:9] *} Y entonces puedes devolver cualquier objeto que necesites, como normalmente lo harías (un `dict`, un modelo de base de datos, etc). @@ -24,7 +24,7 @@ Para hacer eso, puedes crear un response como se describe en [Devolver un Respon Luego establece Cookies en ella, y luego devuélvela: -{* ../../docs_src/response_cookies/tutorial001.py hl[10:12] *} +{* ../../docs_src/response_cookies/tutorial001_py39.py hl[10:12] *} /// tip | Consejo diff --git a/docs/es/docs/advanced/response-directly.md b/docs/es/docs/advanced/response-directly.md index 96b30b915c..2da4e84e70 100644 --- a/docs/es/docs/advanced/response-directly.md +++ b/docs/es/docs/advanced/response-directly.md @@ -54,7 +54,7 @@ Digamos que quieres devolver un response en documentación de Strawberry. diff --git a/docs/es/docs/python-types.md b/docs/es/docs/python-types.md index e51c2352c5..60b50a08ff 100644 --- a/docs/es/docs/python-types.md +++ b/docs/es/docs/python-types.md @@ -22,7 +22,7 @@ Si eres un experto en Python, y ya sabes todo sobre las anotaciones de tipos, sa Comencemos con un ejemplo simple: -{* ../../docs_src/python_types/tutorial001.py *} +{* ../../docs_src/python_types/tutorial001_py39.py *} Llamar a este programa genera: @@ -36,7 +36,7 @@ La función hace lo siguiente: * Convierte la primera letra de cada uno a mayúsculas con `title()`. * Concatena ambos con un espacio en el medio. -{* ../../docs_src/python_types/tutorial001.py hl[2] *} +{* ../../docs_src/python_types/tutorial001_py39.py hl[2] *} ### Edítalo { #edit-it } @@ -78,7 +78,7 @@ Eso es todo. Esas son las "anotaciones de tipos": -{* ../../docs_src/python_types/tutorial002.py hl[1] *} +{* ../../docs_src/python_types/tutorial002_py39.py hl[1] *} Eso no es lo mismo que declarar valores predeterminados como sería con: @@ -106,7 +106,7 @@ Con eso, puedes desplazarte, viendo las opciones, hasta que encuentres la que "t Revisa esta función, ya tiene anotaciones de tipos: -{* ../../docs_src/python_types/tutorial003.py hl[1] *} +{* ../../docs_src/python_types/tutorial003_py39.py hl[1] *} Porque el editor conoce los tipos de las variables, no solo obtienes autocompletado, también obtienes chequeo de errores: @@ -114,7 +114,7 @@ Porque el editor conoce los tipos de las variables, no solo obtienes autocomplet Ahora sabes que debes corregirlo, convertir `age` a un string con `str(age)`: -{* ../../docs_src/python_types/tutorial004.py hl[2] *} +{* ../../docs_src/python_types/tutorial004_py39.py hl[2] *} ## Declaración de tipos { #declaring-types } @@ -133,7 +133,7 @@ Puedes usar, por ejemplo: * `bool` * `bytes` -{* ../../docs_src/python_types/tutorial005.py hl[1] *} +{* ../../docs_src/python_types/tutorial005_py39.py hl[1] *} ### Tipos genéricos con parámetros de tipo { #generic-types-with-type-parameters } @@ -161,56 +161,24 @@ Si puedes usar las **últimas versiones de Python**, utiliza los ejemplos para l Por ejemplo, vamos a definir una variable para ser una `list` de `str`. -//// tab | Python 3.9+ - Declara la variable, con la misma sintaxis de dos puntos (`:`). Como tipo, pon `list`. Como la lista es un tipo que contiene algunos tipos internos, los pones entre corchetes: -```Python hl_lines="1" -{!> ../../docs_src/python_types/tutorial006_py39.py!} -``` - -//// - -//// tab | Python 3.8+ - -De `typing`, importa `List` (con una `L` mayúscula): - -```Python hl_lines="1" -{!> ../../docs_src/python_types/tutorial006.py!} -``` - -Declara la variable, con la misma sintaxis de dos puntos (`:`). - -Como tipo, pon el `List` que importaste de `typing`. - -Como la lista es un tipo que contiene algunos tipos internos, los pones entre corchetes: - -```Python hl_lines="4" -{!> ../../docs_src/python_types/tutorial006.py!} -``` - -//// +{* ../../docs_src/python_types/tutorial006_py39.py hl[1] *} /// info | Información Esos tipos internos en los corchetes se denominan "parámetros de tipo". -En este caso, `str` es el parámetro de tipo pasado a `List` (o `list` en Python 3.9 y superior). +En este caso, `str` es el parámetro de tipo pasado a `list`. /// Eso significa: "la variable `items` es una `list`, y cada uno de los ítems en esta lista es un `str`". -/// tip | Consejo - -Si usas Python 3.9 o superior, no tienes que importar `List` de `typing`, puedes usar el mismo tipo `list` regular en su lugar. - -/// - Al hacer eso, tu editor puede proporcionar soporte incluso mientras procesa elementos de la lista: @@ -225,21 +193,7 @@ Y aún así, el editor sabe que es un `str` y proporciona soporte para eso. Harías lo mismo para declarar `tuple`s y `set`s: -//// tab | Python 3.9+ - -```Python hl_lines="1" -{!> ../../docs_src/python_types/tutorial007_py39.py!} -``` - -//// - -//// tab | Python 3.8+ - -```Python hl_lines="1 4" -{!> ../../docs_src/python_types/tutorial007.py!} -``` - -//// +{* ../../docs_src/python_types/tutorial007_py39.py hl[1] *} Esto significa: @@ -254,21 +208,7 @@ El primer parámetro de tipo es para las claves del `dict`. El segundo parámetro de tipo es para los valores del `dict`: -//// tab | Python 3.9+ - -```Python hl_lines="1" -{!> ../../docs_src/python_types/tutorial008_py39.py!} -``` - -//// - -//// tab | Python 3.8+ - -```Python hl_lines="1 4" -{!> ../../docs_src/python_types/tutorial008.py!} -``` - -//// +{* ../../docs_src/python_types/tutorial008_py39.py hl[1] *} Esto significa: @@ -292,10 +232,10 @@ En Python 3.10 también hay una **nueva sintaxis** donde puedes poner los posibl //// -//// tab | Python 3.8+ +//// tab | Python 3.9+ ```Python hl_lines="1 4" -{!> ../../docs_src/python_types/tutorial008b.py!} +{!> ../../docs_src/python_types/tutorial008b_py39.py!} ``` //// @@ -309,7 +249,7 @@ Puedes declarar que un valor podría tener un tipo, como `str`, pero que tambié En Python 3.6 y posteriores (incluyendo Python 3.10) puedes declararlo importando y usando `Optional` del módulo `typing`. ```Python hl_lines="1 4" -{!../../docs_src/python_types/tutorial009.py!} +{!../../docs_src/python_types/tutorial009_py39.py!} ``` Usar `Optional[str]` en lugar de solo `str` te permitirá al editor ayudarte a detectar errores donde podrías estar asumiendo que un valor siempre es un `str`, cuando en realidad también podría ser `None`. @@ -326,18 +266,18 @@ Esto también significa que en Python 3.10, puedes usar `Something | None`: //// -//// tab | Python 3.8+ +//// tab | Python 3.9+ ```Python hl_lines="1 4" -{!> ../../docs_src/python_types/tutorial009.py!} +{!> ../../docs_src/python_types/tutorial009_py39.py!} ``` //// -//// tab | Python 3.8+ alternativa +//// tab | Python 3.9+ alternativa ```Python hl_lines="1 4" -{!> ../../docs_src/python_types/tutorial009b.py!} +{!> ../../docs_src/python_types/tutorial009b_py39.py!} ``` //// @@ -357,7 +297,7 @@ Se trata solo de las palabras y nombres. Pero esas palabras pueden afectar cómo Como ejemplo, tomemos esta función: -{* ../../docs_src/python_types/tutorial009c.py hl[1,4] *} +{* ../../docs_src/python_types/tutorial009c_py39.py hl[1,4] *} El parámetro `name` está definido como `Optional[str]`, pero **no es opcional**, no puedes llamar a la función sin el parámetro: @@ -390,10 +330,10 @@ Puedes usar los mismos tipos integrados como genéricos (con corchetes y tipos d * `set` * `dict` -Y lo mismo que con Python 3.8, desde el módulo `typing`: +Y, como con versiones anteriores de Python, desde el módulo `typing`: * `Union` -* `Optional` (lo mismo que con Python 3.8) +* `Optional` * ...y otros. En Python 3.10, como alternativa a usar los genéricos `Union` y `Optional`, puedes usar la barra vertical (`|`) para declarar uniones de tipos, eso es mucho mejor y más simple. @@ -409,7 +349,7 @@ Puedes usar los mismos tipos integrados como genéricos (con corchetes y tipos d * `set` * `dict` -Y lo mismo que con Python 3.8, desde el módulo `typing`: +Y generics desde el módulo `typing`: * `Union` * `Optional` @@ -417,29 +357,17 @@ Y lo mismo que con Python 3.8, desde el módulo `typing`: //// -//// tab | Python 3.8+ - -* `List` -* `Tuple` -* `Set` -* `Dict` -* `Union` -* `Optional` -* ...y otros. - -//// - ### Clases como tipos { #classes-as-types } También puedes declarar una clase como el tipo de una variable. Digamos que tienes una clase `Person`, con un nombre: -{* ../../docs_src/python_types/tutorial010.py hl[1:3] *} +{* ../../docs_src/python_types/tutorial010_py39.py hl[1:3] *} Luego puedes declarar una variable para que sea de tipo `Person`: -{* ../../docs_src/python_types/tutorial010.py hl[6] *} +{* ../../docs_src/python_types/tutorial010_py39.py hl[6] *} Y luego, nuevamente, obtienes todo el soporte del editor: @@ -463,29 +391,7 @@ Y obtienes todo el soporte del editor con ese objeto resultante. Un ejemplo de la documentación oficial de Pydantic: -//// tab | Python 3.10+ - -```Python -{!> ../../docs_src/python_types/tutorial011_py310.py!} -``` - -//// - -//// tab | Python 3.9+ - -```Python -{!> ../../docs_src/python_types/tutorial011_py39.py!} -``` - -//// - -//// tab | Python 3.8+ - -```Python -{!> ../../docs_src/python_types/tutorial011.py!} -``` - -//// +{* ../../docs_src/python_types/tutorial011_py310.py *} /// info | Información @@ -507,27 +413,9 @@ Pydantic tiene un comportamiento especial cuando utilizas `Optional` o `Union[So Python también tiene una funcionalidad que permite poner **metadatos adicional** en estas anotaciones de tipos usando `Annotated`. -//// tab | Python 3.9+ +Desde Python 3.9, `Annotated` es parte de la standard library, así que puedes importarlo desde `typing`. -En Python 3.9, `Annotated` es parte de la standard library, así que puedes importarlo desde `typing`. - -```Python hl_lines="1 4" -{!> ../../docs_src/python_types/tutorial013_py39.py!} -``` - -//// - -//// tab | Python 3.8+ - -En versiones por debajo de Python 3.9, importas `Annotated` de `typing_extensions`. - -Ya estará instalado con **FastAPI**. - -```Python hl_lines="1 4" -{!> ../../docs_src/python_types/tutorial013.py!} -``` - -//// +{* ../../docs_src/python_types/tutorial013_py39.py hl[1,4] *} Python en sí no hace nada con este `Annotated`. Y para los editores y otras herramientas, el tipo sigue siendo `str`. diff --git a/docs/es/docs/tutorial/background-tasks.md b/docs/es/docs/tutorial/background-tasks.md index 8cd0767f8e..cc8a2c9cbe 100644 --- a/docs/es/docs/tutorial/background-tasks.md +++ b/docs/es/docs/tutorial/background-tasks.md @@ -15,7 +15,7 @@ Esto incluye, por ejemplo: Primero, importa `BackgroundTasks` y define un parámetro en tu *path operation function* con una declaración de tipo de `BackgroundTasks`: -{* ../../docs_src/background_tasks/tutorial001.py hl[1,13] *} +{* ../../docs_src/background_tasks/tutorial001_py39.py hl[1,13] *} **FastAPI** creará el objeto de tipo `BackgroundTasks` por ti y lo pasará como ese parámetro. @@ -31,13 +31,13 @@ En este caso, la función de tarea escribirá en un archivo (simulando el envío Y como la operación de escritura no usa `async` y `await`, definimos la función con un `def` normal: -{* ../../docs_src/background_tasks/tutorial001.py hl[6:9] *} +{* ../../docs_src/background_tasks/tutorial001_py39.py hl[6:9] *} ## Agregar la tarea en segundo plano { #add-the-background-task } Dentro de tu *path operation function*, pasa tu función de tarea al objeto de *background tasks* con el método `.add_task()`: -{* ../../docs_src/background_tasks/tutorial001.py hl[14] *} +{* ../../docs_src/background_tasks/tutorial001_py39.py hl[14] *} `.add_task()` recibe como argumentos: diff --git a/docs/es/docs/tutorial/body-nested-models.md b/docs/es/docs/tutorial/body-nested-models.md index 04f4b39c4a..0dfd6576f1 100644 --- a/docs/es/docs/tutorial/body-nested-models.md +++ b/docs/es/docs/tutorial/body-nested-models.md @@ -14,35 +14,15 @@ Esto hará que `tags` sea una lista, aunque no declare el tipo de los elementos Pero Python tiene una forma específica de declarar listas con tipos internos, o "parámetros de tipo": -### Importar `List` de typing { #import-typings-list } - -En Python 3.9 y superior, puedes usar el `list` estándar para declarar estas anotaciones de tipo como veremos a continuación. 💡 - -Pero en versiones de Python anteriores a 3.9 (desde 3.6 en adelante), primero necesitas importar `List` del módulo `typing` estándar de Python: - -{* ../../docs_src/body_nested_models/tutorial002.py hl[1] *} - ### Declarar una `list` con un parámetro de tipo { #declare-a-list-with-a-type-parameter } -Para declarar tipos que tienen parámetros de tipo (tipos internos), como `list`, `dict`, `tuple`: - -* Si estás en una versión de Python inferior a 3.9, importa su versión equivalente del módulo `typing` -* Pasa el/los tipo(s) interno(s) como "parámetros de tipo" usando corchetes: `[` y `]` - -En Python 3.9 sería: +Para declarar tipos que tienen parámetros de tipo (tipos internos), como `list`, `dict`, `tuple`, +pasa el/los tipo(s) interno(s) como "parámetros de tipo" usando corchetes: `[` y `]` ```Python my_list: list[str] ``` -En versiones de Python anteriores a 3.9, sería: - -```Python -from typing import List - -my_list: List[str] -``` - Eso es toda la sintaxis estándar de Python para declaraciones de tipo. Usa esa misma sintaxis estándar para atributos de modelos con tipos internos. @@ -178,12 +158,6 @@ Observa cómo `Offer` tiene una lista de `Item`s, que a su vez tienen una lista Si el valor superior del cuerpo JSON que esperas es un `array` JSON (una `list` en Python), puedes declarar el tipo en el parámetro de la función, al igual que en los modelos Pydantic: -```Python -images: List[Image] -``` - -o en Python 3.9 y superior: - ```Python images: list[Image] ``` diff --git a/docs/es/docs/tutorial/body.md b/docs/es/docs/tutorial/body.md index 58877c5c46..06a70dbc79 100644 --- a/docs/es/docs/tutorial/body.md +++ b/docs/es/docs/tutorial/body.md @@ -161,7 +161,7 @@ Los parámetros de la función se reconocerán de la siguiente manera: FastAPI sabrá que el valor de `q` no es requerido debido al valor por defecto `= None`. -El `str | None` (Python 3.10+) o `Union` en `Union[str, None]` (Python 3.8+) no es utilizado por FastAPI para determinar que el valor no es requerido, sabrá que no es requerido porque tiene un valor por defecto de `= None`. +El `str | None` (Python 3.10+) o `Union` en `Union[str, None]` (Python 3.9+) no es utilizado por FastAPI para determinar que el valor no es requerido, sabrá que no es requerido porque tiene un valor por defecto de `= None`. Pero agregar las anotaciones de tipos permitirá que tu editor te brinde un mejor soporte y detecte errores. diff --git a/docs/es/docs/tutorial/cors.md b/docs/es/docs/tutorial/cors.md index d6bc7ea61f..c1a23295e1 100644 --- a/docs/es/docs/tutorial/cors.md +++ b/docs/es/docs/tutorial/cors.md @@ -46,7 +46,7 @@ También puedes especificar si tu backend permite: * Métodos HTTP específicos (`POST`, `PUT`) o todos ellos con el comodín `"*"`. * Headers HTTP específicos o todos ellos con el comodín `"*"`. -{* ../../docs_src/cors/tutorial001.py hl[2,6:11,13:19] *} +{* ../../docs_src/cors/tutorial001_py39.py hl[2,6:11,13:19] *} Los parámetros predeterminados utilizados por la implementación de `CORSMiddleware` son restrictivos por defecto, por lo que necesitarás habilitar explícitamente orígenes, métodos o headers particulares para que los navegadores estén permitidos de usarlos en un contexto de Cross-Domain. diff --git a/docs/es/docs/tutorial/debugging.md b/docs/es/docs/tutorial/debugging.md index 1e57df2092..c31daf40f4 100644 --- a/docs/es/docs/tutorial/debugging.md +++ b/docs/es/docs/tutorial/debugging.md @@ -6,7 +6,7 @@ Puedes conectar el depurador en tu editor, por ejemplo con Visual Studio Code o En tu aplicación de FastAPI, importa y ejecuta `uvicorn` directamente: -{* ../../docs_src/debugging/tutorial001.py hl[1,15] *} +{* ../../docs_src/debugging/tutorial001_py39.py hl[1,15] *} ### Acerca de `__name__ == "__main__"` { #about-name-main } diff --git a/docs/es/docs/tutorial/dependencies/classes-as-dependencies.md b/docs/es/docs/tutorial/dependencies/classes-as-dependencies.md index 37cc2e2133..a3a75efcd9 100644 --- a/docs/es/docs/tutorial/dependencies/classes-as-dependencies.md +++ b/docs/es/docs/tutorial/dependencies/classes-as-dependencies.md @@ -101,7 +101,7 @@ Ahora puedes declarar tu dependencia usando esta clase. Nota cómo escribimos `CommonQueryParams` dos veces en el código anterior: -//// tab | Python 3.8+ +//// tab | Python 3.9+ ```Python commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)] @@ -109,7 +109,7 @@ commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)] //// -//// tab | Python 3.8+ sin `Annotated` +//// tab | Python 3.9+ sin `Annotated` /// tip | Consejo @@ -137,7 +137,7 @@ Es a partir de este que **FastAPI** extraerá los parámetros declarados y es lo En este caso, el primer `CommonQueryParams`, en: -//// tab | Python 3.8+ +//// tab | Python 3.9+ ```Python commons: Annotated[CommonQueryParams, ... @@ -145,7 +145,7 @@ commons: Annotated[CommonQueryParams, ... //// -//// tab | Python 3.8+ sin `Annotated` +//// tab | Python 3.9+ sin `Annotated` /// tip | Consejo @@ -163,7 +163,7 @@ commons: CommonQueryParams ... De hecho, podrías escribir simplemente: -//// tab | Python 3.8+ +//// tab | Python 3.9+ ```Python commons: Annotated[Any, Depends(CommonQueryParams)] @@ -171,7 +171,7 @@ commons: Annotated[Any, Depends(CommonQueryParams)] //// -//// tab | Python 3.8+ sin `Annotated` +//// tab | Python 3.9+ sin `Annotated` /// tip | Consejo @@ -197,7 +197,7 @@ Pero declarar el tipo es recomendable, ya que de esa manera tu editor sabrá lo Pero ves que estamos teniendo algo de repetición de código aquí, escribiendo `CommonQueryParams` dos veces: -//// tab | Python 3.8+ +//// tab | Python 3.9+ ```Python commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)] @@ -205,7 +205,7 @@ commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)] //// -//// tab | Python 3.8+ sin `Annotated` +//// tab | Python 3.9+ sin `Annotated` /// tip | Consejo @@ -225,7 +225,7 @@ Para esos casos específicos, puedes hacer lo siguiente: En lugar de escribir: -//// tab | Python 3.8+ +//// tab | Python 3.9+ ```Python commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)] @@ -233,7 +233,7 @@ commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)] //// -//// tab | Python 3.8+ sin `Annotated` +//// tab | Python 3.9+ sin `Annotated` /// tip | Consejo @@ -249,7 +249,7 @@ commons: CommonQueryParams = Depends(CommonQueryParams) ...escribes: -//// tab | Python 3.8+ +//// tab | Python 3.9+ ```Python commons: Annotated[CommonQueryParams, Depends()] @@ -257,7 +257,7 @@ commons: Annotated[CommonQueryParams, Depends()] //// -//// tab | Python 3.8 sin `Annotated` +//// tab | Python 3.9+ sin `Annotated` /// tip | Consejo diff --git a/docs/es/docs/tutorial/dependencies/dependencies-with-yield.md b/docs/es/docs/tutorial/dependencies/dependencies-with-yield.md index e29c749a5f..aa645daa47 100644 --- a/docs/es/docs/tutorial/dependencies/dependencies-with-yield.md +++ b/docs/es/docs/tutorial/dependencies/dependencies-with-yield.md @@ -29,15 +29,15 @@ Por ejemplo, podrías usar esto para crear una sesión de base de datos y cerrar Solo el código anterior e incluyendo la declaración `yield` se ejecuta antes de crear un response: -{* ../../docs_src/dependencies/tutorial007.py hl[2:4] *} +{* ../../docs_src/dependencies/tutorial007_py39.py hl[2:4] *} El valor generado es lo que se inyecta en *path operations* y otras dependencias: -{* ../../docs_src/dependencies/tutorial007.py hl[4] *} +{* ../../docs_src/dependencies/tutorial007_py39.py hl[4] *} El código posterior a la declaración `yield` se ejecuta después del response: -{* ../../docs_src/dependencies/tutorial007.py hl[5:6] *} +{* ../../docs_src/dependencies/tutorial007_py39.py hl[5:6] *} /// tip | Consejo @@ -57,7 +57,7 @@ Por lo tanto, puedes buscar esa excepción específica dentro de la dependencia Del mismo modo, puedes usar `finally` para asegurarte de que los pasos de salida se ejecuten, sin importar si hubo una excepción o no. -{* ../../docs_src/dependencies/tutorial007.py hl[3,5] *} +{* ../../docs_src/dependencies/tutorial007_py39.py hl[3,5] *} ## Sub-dependencias con `yield` { #sub-dependencies-with-yield } @@ -270,7 +270,7 @@ En Python, puedes crear Context Managers deprecated, pero sin eliminarla, pasa el parámetro `deprecated`: -{* ../../docs_src/path_operation_configuration/tutorial006.py hl[16] *} +{* ../../docs_src/path_operation_configuration/tutorial006_py39.py hl[16] *} Se marcará claramente como deprecado en la documentación interactiva: diff --git a/docs/es/docs/tutorial/path-params-numeric-validations.md b/docs/es/docs/tutorial/path-params-numeric-validations.md index a6f0a4cd3d..569dd03dd0 100644 --- a/docs/es/docs/tutorial/path-params-numeric-validations.md +++ b/docs/es/docs/tutorial/path-params-numeric-validations.md @@ -54,7 +54,7 @@ No importa para **FastAPI**. Detectará los parámetros por sus nombres, tipos y Así que puedes declarar tu función como: -{* ../../docs_src/path_params_numeric_validations/tutorial002.py hl[7] *} +{* ../../docs_src/path_params_numeric_validations/tutorial002_py39.py hl[7] *} Pero ten en cuenta que si usas `Annotated`, no tendrás este problema, no importará ya que no estás usando los valores por defecto de los parámetros de la función para `Query()` o `Path()`. @@ -83,7 +83,7 @@ Pasa `*`, como el primer parámetro de la función. Python no hará nada con ese `*`, pero sabrá que todos los parámetros siguientes deben ser llamados como argumentos de palabras clave (parejas key-value), también conocidos como kwargs. Incluso si no tienen un valor por defecto. -{* ../../docs_src/path_params_numeric_validations/tutorial003.py hl[7] *} +{* ../../docs_src/path_params_numeric_validations/tutorial003_py39.py hl[7] *} ### Mejor con `Annotated` { #better-with-annotated } diff --git a/docs/es/docs/tutorial/path-params.md b/docs/es/docs/tutorial/path-params.md index c49b31c44e..7ba49f3b0b 100644 --- a/docs/es/docs/tutorial/path-params.md +++ b/docs/es/docs/tutorial/path-params.md @@ -2,7 +2,7 @@ Puedes declarar "parámetros" o "variables" de path con la misma sintaxis que se usa en los format strings de Python: -{* ../../docs_src/path_params/tutorial001.py hl[6:7] *} +{* ../../docs_src/path_params/tutorial001_py39.py hl[6:7] *} El valor del parámetro de path `item_id` se pasará a tu función como el argumento `item_id`. @@ -16,7 +16,7 @@ Así que, si ejecutas este ejemplo y vas a Las enumeraciones (o enums) están disponibles en Python desde la versión 3.4. - -/// +{* ../../docs_src/path_params/tutorial005_py39.py hl[1,6:9] *} /// tip | Consejo @@ -158,7 +152,7 @@ Si te estás preguntando, "AlexNet", "ResNet" y "LeNet" son solo nombres de analisado como JSON, ele é lido diretamente como `bytes` e a função `magic_data_reader()` seria a responsável por analisar ele de alguma forma. diff --git a/docs/pt/docs/advanced/response-change-status-code.md b/docs/pt/docs/advanced/response-change-status-code.md index 0f08873f67..ee81f0bfc8 100644 --- a/docs/pt/docs/advanced/response-change-status-code.md +++ b/docs/pt/docs/advanced/response-change-status-code.md @@ -20,7 +20,7 @@ Você pode declarar um parâmetro do tipo `Response` em sua *função de operaç E então você pode definir o `status_code` neste objeto de retorno temporal. -{* ../../docs_src/response_change_status_code/tutorial001.py hl[1,9,12] *} +{* ../../docs_src/response_change_status_code/tutorial001_py39.py hl[1,9,12] *} E então você pode retornar qualquer objeto que você precise, como você faria normalmente (um `dict`, um modelo de banco de dados, etc.). diff --git a/docs/pt/docs/advanced/response-cookies.md b/docs/pt/docs/advanced/response-cookies.md index 41fc000133..67820b433b 100644 --- a/docs/pt/docs/advanced/response-cookies.md +++ b/docs/pt/docs/advanced/response-cookies.md @@ -6,7 +6,7 @@ Você pode declarar um parâmetro do tipo `Response` na sua *função de operaç E então você pode definir cookies nesse objeto de resposta *temporário*. -{* ../../docs_src/response_cookies/tutorial002.py hl[1, 8:9] *} +{* ../../docs_src/response_cookies/tutorial002_py39.py hl[1, 8:9] *} Em seguida, você pode retornar qualquer objeto que precise, como normalmente faria (um `dict`, um modelo de banco de dados, etc). @@ -24,7 +24,7 @@ Para fazer isso, você pode criar uma resposta como descrito em [Retorne uma Res Então, defina os cookies nela e a retorne: -{* ../../docs_src/response_cookies/tutorial001.py hl[10:12] *} +{* ../../docs_src/response_cookies/tutorial001_py39.py hl[10:12] *} /// tip | Dica diff --git a/docs/pt/docs/advanced/response-directly.md b/docs/pt/docs/advanced/response-directly.md index 0c0144e9a1..bbbef2f913 100644 --- a/docs/pt/docs/advanced/response-directly.md +++ b/docs/pt/docs/advanced/response-directly.md @@ -54,7 +54,7 @@ Vamos dizer que você quer retornar uma resposta FastAPI Cloud com um **único comando**; entre na lista de espera, caso ainda não tenha feito isso. 🚀 + +## Login { #login } + +Certifique-se de que você já tem uma conta no **FastAPI Cloud** (nós convidamos você a partir da lista de espera 😉). + +Depois, faça login: + +
+ +```console +$ fastapi login + +You are logged in to FastAPI Cloud 🚀 +``` + +
+ +## Implantar { #deploy } + +Agora, implante sua aplicação, com **um único comando**: + +
+ +```console +$ fastapi deploy + +Deploying to FastAPI Cloud... + +✅ Deployment successful! + +🐔 Ready the chicken! Your app is ready at https://myapp.fastapicloud.dev +``` + +
+ +É isso! Agora você pode acessar sua aplicação nesse URL. ✨ + +## Sobre o FastAPI Cloud { #about-fastapi-cloud } + +O **FastAPI Cloud** é desenvolvido pelo mesmo autor e equipe por trás do **FastAPI**. + +Ele simplifica o processo de **criar**, **implantar** e **acessar** uma API com esforço mínimo. + +Traz a mesma **experiência do desenvolvedor** de criar aplicações com FastAPI para **implantá-las** na nuvem. 🎉 + +Ele também cuidará da maioria das coisas de que você precisaria ao implantar uma aplicação, como: + +* HTTPS +* Replicação, com dimensionamento automático baseado em requests +* etc. + +O FastAPI Cloud é o patrocinador principal e provedor de financiamento dos projetos open source do ecossistema *FastAPI and friends*. ✨ + +## Implantar em outros provedores de nuvem { #deploy-to-other-cloud-providers } + +FastAPI é open source e baseado em padrões. Você pode implantar aplicações FastAPI em qualquer provedor de nuvem que escolher. + +Siga os tutoriais do seu provedor de nuvem para implantar aplicações FastAPI com esse provedor. 🤓 + +## Implantar no seu próprio servidor { #deploy-your-own-server } + +Também vou lhe ensinar, mais adiante neste guia de **Implantação**, todos os detalhes, para que você possa entender o que está acontecendo, o que precisa acontecer, ou como implantar aplicações FastAPI por conta própria, inclusive nos seus próprios servidores. 🤓 diff --git a/docs/pt/docs/how-to/authentication-error-status-code.md b/docs/pt/docs/how-to/authentication-error-status-code.md new file mode 100644 index 0000000000..878a1ca1ac --- /dev/null +++ b/docs/pt/docs/how-to/authentication-error-status-code.md @@ -0,0 +1,17 @@ +# Usar antigos códigos de status de erro de autenticação 403 { #use-old-403-authentication-error-status-codes } + +Antes da versão `0.122.0` do FastAPI, quando os utilitários de segurança integrados retornavam um erro ao cliente após uma falha na autenticação, eles usavam o código de status HTTP `403 Forbidden`. + +A partir da versão `0.122.0` do FastAPI, eles usam o código de status HTTP `401 Unauthorized`, mais apropriado, e retornam um cabeçalho `WWW-Authenticate` adequado na response, seguindo as especificações HTTP, RFC 7235, RFC 9110. + +Mas, se por algum motivo seus clientes dependem do comportamento antigo, você pode voltar a ele sobrescrevendo o método `make_not_authenticated_error` nas suas classes de segurança. + +Por exemplo, você pode criar uma subclasse de `HTTPBearer` que retorne um erro `403 Forbidden` em vez do erro padrão `401 Unauthorized`: + +{* ../../docs_src/authentication_error_status_code/tutorial001_an_py39.py hl[9:13] *} + +/// tip | Dica + +Perceba que a função retorna a instância da exceção, ela não a lança. O lançamento é feito no restante do código interno. + +/// diff --git a/docs/pt/docs/how-to/conditional-openapi.md b/docs/pt/docs/how-to/conditional-openapi.md index da4f5f7642..b475dae6d6 100644 --- a/docs/pt/docs/how-to/conditional-openapi.md +++ b/docs/pt/docs/how-to/conditional-openapi.md @@ -29,7 +29,7 @@ Você pode usar facilmente as mesmas configurações do Pydantic para configurar Por exemplo: -{* ../../docs_src/conditional_openapi/tutorial001.py hl[6,11] *} +{* ../../docs_src/conditional_openapi/tutorial001_py39.py hl[6,11] *} Aqui declaramos a configuração `openapi_url` com o mesmo padrão de `"/openapi.json"`. diff --git a/docs/pt/docs/how-to/configure-swagger-ui.md b/docs/pt/docs/how-to/configure-swagger-ui.md index 163316932f..2d1863c64c 100644 --- a/docs/pt/docs/how-to/configure-swagger-ui.md +++ b/docs/pt/docs/how-to/configure-swagger-ui.md @@ -18,7 +18,7 @@ Sem alterar as configurações, o destaque de sintaxe é habilitado por padrão: Mas você pode desabilitá-lo definindo `syntaxHighlight` como `False`: -{* ../../docs_src/configure_swagger_ui/tutorial001.py hl[3] *} +{* ../../docs_src/configure_swagger_ui/tutorial001_py39.py hl[3] *} ...e então o Swagger UI não mostrará mais o destaque de sintaxe: @@ -28,7 +28,7 @@ Mas você pode desabilitá-lo definindo `syntaxHighlight` como `False`: Da mesma forma que você pode definir o tema de destaque de sintaxe com a chave `"syntaxHighlight.theme"` (observe que há um ponto no meio): -{* ../../docs_src/configure_swagger_ui/tutorial002.py hl[3] *} +{* ../../docs_src/configure_swagger_ui/tutorial002_py39.py hl[3] *} Essa configuração alteraria o tema de cores de destaque de sintaxe: @@ -46,7 +46,7 @@ Você pode substituir qualquer um deles definindo um valor diferente no argument Por exemplo, para desabilitar `deepLinking` você pode passar essas configurações para `swagger_ui_parameters`: -{* ../../docs_src/configure_swagger_ui/tutorial003.py hl[3] *} +{* ../../docs_src/configure_swagger_ui/tutorial003_py39.py hl[3] *} ## Outros parâmetros da UI do Swagger { #other-swagger-ui-parameters } diff --git a/docs/pt/docs/how-to/custom-docs-ui-assets.md b/docs/pt/docs/how-to/custom-docs-ui-assets.md index 30224c72bb..adda9eca50 100644 --- a/docs/pt/docs/how-to/custom-docs-ui-assets.md +++ b/docs/pt/docs/how-to/custom-docs-ui-assets.md @@ -18,7 +18,7 @@ O primeiro passo é desativar a documentação automática, pois por padrão, el Para desativá-los, defina suas URLs como `None` ao criar sua aplicação FastAPI: -{* ../../docs_src/custom_docs_ui/tutorial001.py hl[8] *} +{* ../../docs_src/custom_docs_ui/tutorial001_py39.py hl[8] *} ### Incluir a documentação personalizada { #include-the-custom-docs } @@ -34,7 +34,7 @@ Você pode reutilizar as funções internas do FastAPI para criar as páginas HT E de forma semelhante para o ReDoc... -{* ../../docs_src/custom_docs_ui/tutorial001.py hl[2:6,11:19,22:24,27:33] *} +{* ../../docs_src/custom_docs_ui/tutorial001_py39.py hl[2:6,11:19,22:24,27:33] *} /// tip | Dica @@ -50,7 +50,7 @@ Swagger UI lidará com isso nos bastidores para você, mas ele precisa desse aux Agora, para poder testar se tudo funciona, crie uma *operação de rota*: -{* ../../docs_src/custom_docs_ui/tutorial001.py hl[36:38] *} +{* ../../docs_src/custom_docs_ui/tutorial001_py39.py hl[36:38] *} ### Teste { #test-it } @@ -118,7 +118,7 @@ Depois disso, sua estrutura de arquivos deve se parecer com: * Importe `StaticFiles`. * "Monte" a instância `StaticFiles()` em um caminho específico. -{* ../../docs_src/custom_docs_ui/tutorial002.py hl[7,11] *} +{* ../../docs_src/custom_docs_ui/tutorial002_py39.py hl[7,11] *} ### Teste os arquivos estáticos { #test-the-static-files } @@ -144,7 +144,7 @@ Da mesma forma que ao usar um CDN personalizado, o primeiro passo é desativar a Para desativá-los, defina suas URLs como `None` ao criar sua aplicação FastAPI: -{* ../../docs_src/custom_docs_ui/tutorial002.py hl[9] *} +{* ../../docs_src/custom_docs_ui/tutorial002_py39.py hl[9] *} ### Incluir a documentação personalizada para arquivos estáticos { #include-the-custom-docs-for-static-files } @@ -160,7 +160,7 @@ Novamente, você pode reutilizar as funções internas do FastAPI para criar as E de forma semelhante para o ReDoc... -{* ../../docs_src/custom_docs_ui/tutorial002.py hl[2:6,14:22,25:27,30:36] *} +{* ../../docs_src/custom_docs_ui/tutorial002_py39.py hl[2:6,14:22,25:27,30:36] *} /// tip | Dica @@ -176,7 +176,7 @@ Swagger UI lidará com isso nos bastidores para você, mas ele precisa desse aux Agora, para poder testar se tudo funciona, crie uma *operação de rota*: -{* ../../docs_src/custom_docs_ui/tutorial002.py hl[39:41] *} +{* ../../docs_src/custom_docs_ui/tutorial002_py39.py hl[39:41] *} ### Teste a UI de Arquivos Estáticos { #test-static-files-ui } diff --git a/docs/pt/docs/how-to/extending-openapi.md b/docs/pt/docs/how-to/extending-openapi.md index 54d56b95ae..b1b50ce654 100644 --- a/docs/pt/docs/how-to/extending-openapi.md +++ b/docs/pt/docs/how-to/extending-openapi.md @@ -43,19 +43,19 @@ Por exemplo, vamos adicionar documentação do Strawberry. diff --git a/docs/pt/docs/python-types.md b/docs/pt/docs/python-types.md index 3e2d1ccb30..fc983d1df1 100644 --- a/docs/pt/docs/python-types.md +++ b/docs/pt/docs/python-types.md @@ -22,7 +22,7 @@ Se você é um especialista em Python e já sabe tudo sobre type hints, pule par Vamos começar com um exemplo simples: -{* ../../docs_src/python_types/tutorial001.py *} +{* ../../docs_src/python_types/tutorial001_py39.py *} A chamada deste programa gera: @@ -36,7 +36,7 @@ A função faz o seguinte: * Converte a primeira letra de cada uma em maiúsculas com `title()`. * Concatena com um espaço no meio. -{* ../../docs_src/python_types/tutorial001.py hl[2] *} +{* ../../docs_src/python_types/tutorial001_py39.py hl[2] *} ### Edite-o { #edit-it } @@ -78,7 +78,7 @@ para: Esses são os "type hints": -{* ../../docs_src/python_types/tutorial002.py hl[1] *} +{* ../../docs_src/python_types/tutorial002_py39.py hl[1] *} Isso não é o mesmo que declarar valores padrão como seria com: @@ -106,7 +106,7 @@ Com isso, você pode rolar, vendo as opções, até encontrar o que "soa familia Verifique esta função, ela já possui type hints: -{* ../../docs_src/python_types/tutorial003.py hl[1] *} +{* ../../docs_src/python_types/tutorial003_py39.py hl[1] *} Como o editor conhece os tipos de variáveis, você não obtém apenas o preenchimento automático, mas também as verificações de erro: @@ -114,7 +114,7 @@ Como o editor conhece os tipos de variáveis, você não obtém apenas o preench Agora você sabe que precisa corrigí-lo, converta `age` em uma string com `str(age)`: -{* ../../docs_src/python_types/tutorial004.py hl[2] *} +{* ../../docs_src/python_types/tutorial004_py39.py hl[2] *} ## Declarando Tipos { #declaring-types } @@ -133,7 +133,7 @@ Você pode usar, por exemplo: * `bool` * `bytes` -{* ../../docs_src/python_types/tutorial005.py hl[1] *} +{* ../../docs_src/python_types/tutorial005_py39.py hl[1] *} ### Tipos genéricos com parâmetros de tipo { #generic-types-with-type-parameters } @@ -161,56 +161,24 @@ Se você pode utilizar a **versão mais recente do Python**, utilize os exemplos Por exemplo, vamos definir uma variável para ser uma `list` de `str`. -//// tab | Python 3.9+ +Declare a variável, com a mesma sintaxe com dois pontos (`:`). -Declare uma variável com a mesma sintaxe com dois pontos (`:`) +Como o tipo, coloque `list`. -Como tipo, coloque `list`. +Como a lista é um tipo que contém tipos internos, você os coloca entre colchetes: -Como a lista é o tipo que contém algum tipo interno, você coloca o tipo dentro de colchetes: - -```Python hl_lines="1" -{!> ../../docs_src/python_types/tutorial006_py39.py!} -``` - -//// - -//// tab | Python 3.8+ - -De `typing`, importe `List` (com o `L` maiúsculo): - -```Python hl_lines="1" -{!> ../../docs_src/python_types/tutorial006.py!} -``` - -Declare uma variável com a mesma sintaxe com dois pontos (`:`) - -Como tipo, coloque o `List` que você importou de `typing`. - -Como a lista é o tipo que contém algum tipo interno, você coloca o tipo dentro de colchetes: - -```Python hl_lines="4" -{!> ../../docs_src/python_types/tutorial006.py!} -``` - -//// +{* ../../docs_src/python_types/tutorial006_py39.py hl[1] *} /// info | Informação Estes tipos internos dentro dos colchetes são chamados "parâmetros de tipo" (type parameters). -Neste caso, `str` é o parâmetro de tipo passado para `List` (ou `list` no Python 3.9 ou superior). +Neste caso, `str` é o parâmetro de tipo passado para `list`. /// Isso significa: "a variável `items` é uma `list`, e cada um dos itens desta lista é uma `str`". -/// tip | Dica - -Se você usa o Python 3.9 ou superior, você não precisa importar `List` de `typing`. Você pode utilizar o mesmo tipo `list` no lugar. - -/// - Ao fazer isso, seu editor pode fornecer suporte mesmo durante o processamento de itens da lista: @@ -225,21 +193,7 @@ E, ainda assim, o editor sabe que é um `str` e fornece suporte para isso. Você faria o mesmo para declarar `tuple`s e `set`s: -//// tab | Python 3.9+ - -```Python hl_lines="1" -{!> ../../docs_src/python_types/tutorial007_py39.py!} -``` - -//// - -//// tab | Python 3.8+ - -```Python hl_lines="1 4" -{!> ../../docs_src/python_types/tutorial007.py!} -``` - -//// +{* ../../docs_src/python_types/tutorial007_py39.py hl[1] *} Isso significa que: @@ -254,21 +208,7 @@ O primeiro parâmetro de tipo é para as chaves do `dict`. O segundo parâmetro de tipo é para os valores do `dict`: -//// tab | Python 3.9+ - -```Python hl_lines="1" -{!> ../../docs_src/python_types/tutorial008_py39.py!} -``` - -//// - -//// tab | Python 3.8+ - -```Python hl_lines="1 4" -{!> ../../docs_src/python_types/tutorial008.py!} -``` - -//// +{* ../../docs_src/python_types/tutorial008_py39.py hl[1] *} Isso significa que: @@ -292,10 +232,10 @@ No Python 3.10 também existe uma **nova sintaxe** onde você pode colocar os po //// -//// tab | Python 3.8+ +//// tab | Python 3.9+ ```Python hl_lines="1 4" -{!> ../../docs_src/python_types/tutorial008b.py!} +{!> ../../docs_src/python_types/tutorial008b_py39.py!} ``` //// @@ -309,7 +249,7 @@ Você pode declarar que um valor pode ter um tipo, como `str`, mas que ele tamb No Python 3.6 e superior (incluindo o Python 3.10) você pode declará-lo importando e utilizando `Optional` do módulo `typing`. ```Python hl_lines="1 4" -{!../../docs_src/python_types/tutorial009.py!} +{!../../docs_src/python_types/tutorial009_py39.py!} ``` O uso de `Optional[str]` em vez de apenas `str` permitirá que o editor o ajude a detectar erros, onde você pode estar assumindo que um valor é sempre um `str`, quando na verdade também pode ser `None`. @@ -326,18 +266,18 @@ Isso também significa que no Python 3.10, você pode utilizar `Something | None //// -//// tab | Python 3.8+ +//// tab | Python 3.9+ ```Python hl_lines="1 4" -{!> ../../docs_src/python_types/tutorial009.py!} +{!> ../../docs_src/python_types/tutorial009_py39.py!} ``` //// -//// tab | Python 3.8+ alternativa +//// tab | Python 3.9+ alternativa ```Python hl_lines="1 4" -{!> ../../docs_src/python_types/tutorial009b.py!} +{!> ../../docs_src/python_types/tutorial009b_py39.py!} ``` //// @@ -357,7 +297,7 @@ Isso é apenas sobre palavras e nomes. Mas estas palavras podem afetar como os s Por exemplo, vamos pegar esta função: -{* ../../docs_src/python_types/tutorial009c.py hl[1,4] *} +{* ../../docs_src/python_types/tutorial009c_py39.py hl[1,4] *} O parâmetro `name` é definido como `Optional[str]`, mas ele **não é opcional**, você não pode chamar a função sem o parâmetro: @@ -390,10 +330,10 @@ Você pode utilizar os mesmos tipos internos como genéricos (com colchetes e ti * `set` * `dict` -E o mesmo como no Python 3.8, do módulo `typing`: +E o mesmo que com versões anteriores do Python, do módulo `typing`: * `Union` -* `Optional` (o mesmo que com o 3.8) +* `Optional` * ...entre outros. No Python 3.10, como uma alternativa para a utilização dos genéricos `Union` e `Optional`, você pode usar a barra vertical (`|`) para declarar uniões de tipos. Isso é muito melhor e mais simples. @@ -409,7 +349,7 @@ Você pode utilizar os mesmos tipos internos como genéricos (com colchetes e ti * `set` * `dict` -E o mesmo como no Python 3.8, do módulo `typing`: +E genéricos do módulo `typing`: * `Union` * `Optional` @@ -417,31 +357,19 @@ E o mesmo como no Python 3.8, do módulo `typing`: //// -//// tab | Python 3.8+ - -* `List` -* `Tuple` -* `Set` -* `Dict` -* `Union` -* `Optional` -* ...entre outros. - -//// - ### Classes como tipos { #classes-as-types } Você também pode declarar uma classe como o tipo de uma variável. Digamos que você tenha uma classe `Person`, com um nome: -{* ../../docs_src/python_types/tutorial010.py hl[1:3] *} +{* ../../docs_src/python_types/tutorial010_py39.py hl[1:3] *} Então você pode declarar que uma variável é do tipo `Person`: -{* ../../docs_src/python_types/tutorial010.py hl[6] *} +{* ../../docs_src/python_types/tutorial010_py39.py hl[6] *} -E então, novamente, você recebe todo o suporte do editor: +E então, novamente, você recebe todo o apoio do editor: @@ -461,31 +389,9 @@ Em seguida, você cria uma instância dessa classe com alguns valores e ela os v E você recebe todo o suporte do editor com esse objeto resultante. -Retirado dos documentos oficiais dos Pydantic: +Um exemplo da documentação oficial do Pydantic: -//// tab | Python 3.10+ - -```Python -{!> ../../docs_src/python_types/tutorial011_py310.py!} -``` - -//// - -//// tab | Python 3.9+ - -```Python -{!> ../../docs_src/python_types/tutorial011_py39.py!} -``` - -//// - -//// tab | Python 3.8+ - -```Python -{!> ../../docs_src/python_types/tutorial011.py!} -``` - -//// +{* ../../docs_src/python_types/tutorial011_py310.py *} /// info | Informação @@ -507,27 +413,9 @@ O Pydantic tem um comportamento especial quando você usa `Optional` ou `Union[S O Python possui uma funcionalidade que nos permite incluir **metadados adicionais** nos type hints utilizando `Annotated`. -//// tab | Python 3.9+ +Desde o Python 3.9, `Annotated` faz parte da biblioteca padrão, então você pode importá-lo de `typing`. -No Python 3.9, `Annotated` é parte da biblioteca padrão, então você pode importá-lo de `typing`. - -```Python hl_lines="1 4" -{!> ../../docs_src/python_types/tutorial013_py39.py!} -``` - -//// - -//// tab | Python 3.8+ - -Em versões abaixo do Python 3.9, você importa `Annotated` de `typing_extensions`. - -Ele já estará instalado com o **FastAPI**. - -```Python hl_lines="1 4" -{!> ../../docs_src/python_types/tutorial013.py!} -``` - -//// +{* ../../docs_src/python_types/tutorial013_py39.py hl[1,4] *} O Python em si não faz nada com este `Annotated`. E para editores e outras ferramentas, o tipo ainda é `str`. diff --git a/docs/pt/docs/tutorial/background-tasks.md b/docs/pt/docs/tutorial/background-tasks.md index af0c8b2acd..34805364b4 100644 --- a/docs/pt/docs/tutorial/background-tasks.md +++ b/docs/pt/docs/tutorial/background-tasks.md @@ -15,7 +15,7 @@ Isso inclui, por exemplo: Primeiro, importe `BackgroundTasks` e defina um parâmetro na sua *função de operação de rota* com uma declaração de tipo `BackgroundTasks`: -{* ../../docs_src/background_tasks/tutorial001.py hl[1,13] *} +{* ../../docs_src/background_tasks/tutorial001_py39.py hl[1,13] *} O **FastAPI** criará o objeto do tipo `BackgroundTasks` para você e o passará como esse parâmetro. @@ -31,13 +31,13 @@ Neste caso, a função da tarefa escreverá em um arquivo (simulando o envio de E como a operação de escrita não usa `async` e `await`, definimos a função com um `def` normal: -{* ../../docs_src/background_tasks/tutorial001.py hl[6:9] *} +{* ../../docs_src/background_tasks/tutorial001_py39.py hl[6:9] *} ## Adicione a tarefa em segundo plano { #add-the-background-task } Dentro da sua *função de operação de rota*, passe sua função de tarefa para o objeto de *tarefas em segundo plano* com o método `.add_task()`: -{* ../../docs_src/background_tasks/tutorial001.py hl[14] *} +{* ../../docs_src/background_tasks/tutorial001_py39.py hl[14] *} O `.add_task()` recebe como argumentos: diff --git a/docs/pt/docs/tutorial/body-nested-models.md b/docs/pt/docs/tutorial/body-nested-models.md index 4f3ca661fb..f2bec19a2f 100644 --- a/docs/pt/docs/tutorial/body-nested-models.md +++ b/docs/pt/docs/tutorial/body-nested-models.md @@ -14,35 +14,15 @@ Isso fará com que tags seja uma lista de itens mesmo sem declarar o tipo dos el Mas o Python tem uma maneira específica de declarar listas com tipos internos ou "parâmetros de tipo": -### Importe `List` do typing { #import-typings-list } - -No Python 3.9 e superior você pode usar a `list` padrão para declarar essas anotações de tipo, como veremos abaixo. 💡 - -Mas nas versões do Python anteriores à 3.9 (3.6 e superiores), primeiro é necessário importar `List` do módulo padrão `typing` do Python: - -{* ../../docs_src/body_nested_models/tutorial002.py hl[1] *} - ### Declare uma `list` com um parâmetro de tipo { #declare-a-list-with-a-type-parameter } -Para declarar tipos que têm parâmetros de tipo (tipos internos), como `list`, `dict`, `tuple`: - -* Se você estiver em uma versão do Python inferior a 3.9, importe a versão equivalente do módulo `typing` -* Passe o(s) tipo(s) interno(s) como "parâmetros de tipo" usando colchetes: `[` e `]` - -No Python 3.9, seria: +Para declarar tipos que têm parâmetros de tipo (tipos internos), como `list`, `dict`, `tuple`, +passe o(s) tipo(s) interno(s) como "parâmetros de tipo" usando colchetes: `[` e `]` ```Python my_list: list[str] ``` -Em versões do Python anteriores à 3.9, seria: - -```Python -from typing import List - -my_list: List[str] -``` - Essa é a sintaxe padrão do Python para declarações de tipo. Use a mesma sintaxe padrão para atributos de modelo com tipos internos. @@ -178,12 +158,6 @@ Observe como `Offer` tem uma lista de `Item`s, que por sua vez têm uma lista op Se o valor de primeiro nível do corpo JSON que você espera for um `array` do JSON (uma` lista` do Python), você pode declarar o tipo no parâmetro da função, da mesma forma que nos modelos do Pydantic: -```Python -images: List[Image] -``` - -ou no Python 3.9 e superior: - ```Python images: list[Image] ``` diff --git a/docs/pt/docs/tutorial/body.md b/docs/pt/docs/tutorial/body.md index ef00b9a7a7..1330f4458f 100644 --- a/docs/pt/docs/tutorial/body.md +++ b/docs/pt/docs/tutorial/body.md @@ -161,7 +161,7 @@ Os parâmetros da função serão reconhecidos conforme abaixo: O FastAPI saberá que o valor de `q` não é obrigatório por causa do valor padrão `= None`. -O `str | None` (Python 3.10+) ou o `Union` em `Union[str, None]` (Python 3.8+) não é utilizado pelo FastAPI para determinar que o valor não é obrigatório, ele saberá que não é obrigatório porque tem um valor padrão `= None`. +O `str | None` (Python 3.10+) ou o `Union` em `Union[str, None]` (Python 3.9+) não é utilizado pelo FastAPI para determinar que o valor não é obrigatório, ele saberá que não é obrigatório porque tem um valor padrão `= None`. Mas adicionar as anotações de tipo permitirá ao seu editor oferecer um suporte melhor e detectar erros. diff --git a/docs/pt/docs/tutorial/cors.md b/docs/pt/docs/tutorial/cors.md index c08191db14..0f99db888e 100644 --- a/docs/pt/docs/tutorial/cors.md +++ b/docs/pt/docs/tutorial/cors.md @@ -46,7 +46,7 @@ Você também pode especificar se o seu backend permite: * Métodos HTTP específicos (`POST`, `PUT`) ou todos eles com o curinga `"*"`. * Cabeçalhos HTTP específicos ou todos eles com o curinga `"*"`. -{* ../../docs_src/cors/tutorial001.py hl[2,6:11,13:19] *} +{* ../../docs_src/cors/tutorial001_py39.py hl[2,6:11,13:19] *} Os parâmetros padrão usados ​​pela implementação `CORSMiddleware` são restritivos por padrão, então você precisará habilitar explicitamente as origens, métodos ou cabeçalhos específicos para que os navegadores tenham permissão para usá-los em um contexto cross domain. diff --git a/docs/pt/docs/tutorial/debugging.md b/docs/pt/docs/tutorial/debugging.md index 21d1d527bd..e39c7d1280 100644 --- a/docs/pt/docs/tutorial/debugging.md +++ b/docs/pt/docs/tutorial/debugging.md @@ -6,7 +6,7 @@ Você pode conectar o depurador no seu editor, por exemplo, com o Visual Studio Em sua aplicação FastAPI, importe e execute `uvicorn` diretamente: -{* ../../docs_src/debugging/tutorial001.py hl[1,15] *} +{* ../../docs_src/debugging/tutorial001_py39.py hl[1,15] *} ### Sobre `__name__ == "__main__"` { #about-name-main } diff --git a/docs/pt/docs/tutorial/dependencies/classes-as-dependencies.md b/docs/pt/docs/tutorial/dependencies/classes-as-dependencies.md index aa26d158f4..c30d0b5f08 100644 --- a/docs/pt/docs/tutorial/dependencies/classes-as-dependencies.md +++ b/docs/pt/docs/tutorial/dependencies/classes-as-dependencies.md @@ -101,7 +101,7 @@ O **FastAPI** chama a classe `CommonQueryParams`. Isso cria uma "instância" des Perceba como escrevemos `CommonQueryParams` duas vezes no código abaixo: -//// tab | Python 3.8+ +//// tab | Python 3.9+ ```Python commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)] @@ -109,7 +109,7 @@ commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)] //// -//// tab | Python 3.8+ non-Annotated +//// tab | Python 3.9+ non-Annotated /// tip | Dica @@ -137,7 +137,7 @@ O último `CommonQueryParams`, em: Nesse caso, o primeiro `CommonQueryParams`, em: -//// tab | Python 3.8+ +//// tab | Python 3.9+ ```Python commons: Annotated[CommonQueryParams, ... @@ -145,7 +145,7 @@ commons: Annotated[CommonQueryParams, ... //// -//// tab | Python 3.8+ non-Annotated +//// tab | Python 3.9+ non-Annotated /// tip | Dica @@ -163,7 +163,7 @@ commons: CommonQueryParams ... Na verdade você poderia escrever apenas: -//// tab | Python 3.8+ +//// tab | Python 3.9+ ```Python commons: Annotated[Any, Depends(CommonQueryParams)] @@ -171,7 +171,7 @@ commons: Annotated[Any, Depends(CommonQueryParams)] //// -//// tab | Python 3.8+ non-Annotated +//// tab | Python 3.9+ non-Annotated /// tip | Dica @@ -197,7 +197,7 @@ Mas declarar o tipo é encorajado por que é a forma que o seu editor de texto s Mas você pode ver que temos uma repetição do código neste exemplo, escrevendo `CommonQueryParams` duas vezes: -//// tab | Python 3.8+ +//// tab | Python 3.9+ ```Python commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)] @@ -205,7 +205,7 @@ commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)] //// -//// tab | Python 3.8+ non-Annotated +//// tab | Python 3.9+ non-Annotated /// tip | Dica @@ -225,7 +225,7 @@ Para esses casos específicos, você pode fazer o seguinte: Em vez de escrever: -//// tab | Python 3.8+ +//// tab | Python 3.9+ ```Python commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)] @@ -233,7 +233,7 @@ commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)] //// -//// tab | Python 3.8+ non-Annotated +//// tab | Python 3.9+ non-Annotated /// tip | Dica @@ -249,7 +249,7 @@ commons: CommonQueryParams = Depends(CommonQueryParams) ...escreva: -//// tab | Python 3.8+ +//// tab | Python 3.9+ ```Python commons: Annotated[CommonQueryParams, Depends()] @@ -257,7 +257,7 @@ commons: Annotated[CommonQueryParams, Depends()] //// -//// tab | Python 3.8 non-Annotated +//// tab | Python 3.9+ non-Annotated /// tip | Dica diff --git a/docs/pt/docs/tutorial/dependencies/dependencies-with-yield.md b/docs/pt/docs/tutorial/dependencies/dependencies-with-yield.md index 0aedcfb31e..3678730139 100644 --- a/docs/pt/docs/tutorial/dependencies/dependencies-with-yield.md +++ b/docs/pt/docs/tutorial/dependencies/dependencies-with-yield.md @@ -29,15 +29,15 @@ Por exemplo, você poderia utilizar isso para criar uma sessão do banco de dado Apenas o código anterior à declaração com `yield` e o código contendo essa declaração são executados antes de criar uma resposta: -{* ../../docs_src/dependencies/tutorial007.py hl[2:4] *} +{* ../../docs_src/dependencies/tutorial007_py39.py hl[2:4] *} O valor gerado (yielded) é o que é injetado nas *operações de rota* e outras dependências: -{* ../../docs_src/dependencies/tutorial007.py hl[4] *} +{* ../../docs_src/dependencies/tutorial007_py39.py hl[4] *} O código após o `yield` é executado após a resposta: -{* ../../docs_src/dependencies/tutorial007.py hl[5:6] *} +{* ../../docs_src/dependencies/tutorial007_py39.py hl[5:6] *} /// tip | Dica @@ -57,7 +57,7 @@ Então, você pode procurar por essa exceção específica dentro da dependênci Da mesma forma, você pode utilizar `finally` para garantir que os passos de saída são executados, com ou sem exceções. -{* ../../docs_src/dependencies/tutorial007.py hl[3,5] *} +{* ../../docs_src/dependencies/tutorial007_py39.py hl[3,5] *} ## Subdependências com `yield` { #sub-dependencies-with-yield } @@ -269,7 +269,7 @@ Em Python, você pode criar Gerenciadores de Contexto ao descontinuada, mas sem removê-la, passe o parâmetro `deprecated`: -{* ../../docs_src/path_operation_configuration/tutorial006.py hl[16] *} +{* ../../docs_src/path_operation_configuration/tutorial006_py39.py hl[16] *} Ela será claramente marcada como descontinuada nas documentações interativas: diff --git a/docs/pt/docs/tutorial/path-params-numeric-validations.md b/docs/pt/docs/tutorial/path-params-numeric-validations.md index cec744fd5e..9f12ba38fe 100644 --- a/docs/pt/docs/tutorial/path-params-numeric-validations.md +++ b/docs/pt/docs/tutorial/path-params-numeric-validations.md @@ -54,7 +54,7 @@ Isso não faz diferença para o **FastAPI**. Ele vai detectar os parâmetros pel Então, você pode declarar sua função assim: -{* ../../docs_src/path_params_numeric_validations/tutorial002.py hl[7] *} +{* ../../docs_src/path_params_numeric_validations/tutorial002_py39.py hl[7] *} Mas tenha em mente que, se você usar `Annotated`, você não terá esse problema, não fará diferença, pois você não está usando valores padrão de parâmetros de função para `Query()` ou `Path()`. @@ -83,7 +83,7 @@ Passe `*`, como o primeiro parâmetro da função. O Python não fará nada com esse `*`, mas saberá que todos os parâmetros seguintes devem ser chamados como argumentos nomeados (pares chave-valor), também conhecidos como kwargs. Mesmo que eles não tenham um valor padrão. -{* ../../docs_src/path_params_numeric_validations/tutorial003.py hl[7] *} +{* ../../docs_src/path_params_numeric_validations/tutorial003_py39.py hl[7] *} ### Melhor com `Annotated` { #better-with-annotated } diff --git a/docs/pt/docs/tutorial/path-params.md b/docs/pt/docs/tutorial/path-params.md index d795d5b2a0..1f47ca6e59 100644 --- a/docs/pt/docs/tutorial/path-params.md +++ b/docs/pt/docs/tutorial/path-params.md @@ -2,7 +2,7 @@ Você pode declarar "parâmetros" ou "variáveis" de path com a mesma sintaxe usada por strings de formatação do Python: -{* ../../docs_src/path_params/tutorial001.py hl[6:7] *} +{* ../../docs_src/path_params/tutorial001_py39.py hl[6:7] *} O valor do parâmetro de path `item_id` será passado para a sua função como o argumento `item_id`. @@ -16,7 +16,7 @@ Então, se você executar este exemplo e acessar Enumerations (ou enums) estão disponíveis no Python desde a versão 3.4. -/// +{* ../../docs_src/path_params/tutorial005_py39.py hl[1,6:9] *} /// tip | Dica Se você está se perguntando, "AlexNet", "ResNet" e "LeNet" são apenas nomes de modelos de Aprendizado de Máquina. @@ -146,7 +142,7 @@ Se você está se perguntando, "AlexNet", "ResNet" e "LeNet" são apenas nomes d Em seguida, crie um *parâmetro de path* com anotação de tipo usando a classe enum que você criou (`ModelName`): -{* ../../docs_src/path_params/tutorial005.py hl[16] *} +{* ../../docs_src/path_params/tutorial005_py39.py hl[16] *} ### Verifique a documentação { #check-the-docs } @@ -162,13 +158,13 @@ O valor do *parâmetro de path* será um *membro de enumeração*. Você pode compará-lo com o *membro de enumeração* no seu enum `ModelName` criado: -{* ../../docs_src/path_params/tutorial005.py hl[17] *} +{* ../../docs_src/path_params/tutorial005_py39.py hl[17] *} #### Obtenha o valor da enumeração { #get-the-enumeration-value } Você pode obter o valor real (um `str` neste caso) usando `model_name.value`, ou, em geral, `your_enum_member.value`: -{* ../../docs_src/path_params/tutorial005.py hl[20] *} +{* ../../docs_src/path_params/tutorial005_py39.py hl[20] *} /// tip | Dica Você também pode acessar o valor `"lenet"` com `ModelName.lenet.value`. @@ -180,7 +176,7 @@ Você pode retornar *membros de enum* da sua *operação de rota*, até mesmo an Eles serão convertidos para seus valores correspondentes (strings neste caso) antes de serem retornados ao cliente: -{* ../../docs_src/path_params/tutorial005.py hl[18,21,23] *} +{* ../../docs_src/path_params/tutorial005_py39.py hl[18,21,23] *} No seu cliente, você receberá uma resposta JSON como: @@ -219,7 +215,7 @@ Nesse caso, o nome do parâmetro é `file_path`, e a última parte, `:path`, diz Então, você pode usá-lo com: -{* ../../docs_src/path_params/tutorial004.py hl[6] *} +{* ../../docs_src/path_params/tutorial004_py39.py hl[6] *} /// tip | Dica Você pode precisar que o parâmetro contenha `/home/johndoe/myfile.txt`, com uma barra inicial (`/`). diff --git a/docs/pt/docs/tutorial/query-params-str-validations.md b/docs/pt/docs/tutorial/query-params-str-validations.md index 948f8ca8fa..5ec1b1b55e 100644 --- a/docs/pt/docs/tutorial/query-params-str-validations.md +++ b/docs/pt/docs/tutorial/query-params-str-validations.md @@ -55,7 +55,7 @@ q: str | None = None //// -//// tab | Python 3.8+ +//// tab | Python 3.9+ ```Python q: Union[str, None] = None @@ -73,7 +73,7 @@ q: Annotated[str | None] = None //// -//// tab | Python 3.8+ +//// tab | Python 3.9+ ```Python q: Annotated[Union[str, None]] = None diff --git a/docs/pt/docs/tutorial/query-params.md b/docs/pt/docs/tutorial/query-params.md index 5a3fed0359..8826602a25 100644 --- a/docs/pt/docs/tutorial/query-params.md +++ b/docs/pt/docs/tutorial/query-params.md @@ -2,7 +2,7 @@ Quando você declara outros parâmetros na função que não fazem parte dos parâmetros da rota, esses parâmetros são automaticamente interpretados como parâmetros de "consulta". -{* ../../docs_src/query_params/tutorial001.py hl[9] *} +{* ../../docs_src/query_params/tutorial001_py39.py hl[9] *} A consulta é o conjunto de pares chave-valor que vai depois de `?` na URL, separado pelo caractere `&`. @@ -127,7 +127,7 @@ Caso você não queira adicionar um valor específico mas queira apenas torná-l Porém, quando você quiser fazer com que o parâmetro de consulta seja obrigatório, você pode simplesmente não declarar nenhum valor como padrão. -{* ../../docs_src/query_params/tutorial005.py hl[6:7] *} +{* ../../docs_src/query_params/tutorial005_py39.py hl[6:7] *} Aqui o parâmetro de consulta `needy` é um valor obrigatório, do tipo `str`. diff --git a/docs/pt/docs/tutorial/response-model.md b/docs/pt/docs/tutorial/response-model.md index 5958240e4c..dc66bb46c4 100644 --- a/docs/pt/docs/tutorial/response-model.md +++ b/docs/pt/docs/tutorial/response-model.md @@ -183,7 +183,7 @@ Pode haver casos em que você retorna algo que não é um campo Pydantic válido O caso mais comum seria [retornar uma Response diretamente, conforme explicado posteriormente na documentação avançada](../advanced/response-directly.md){.internal-link target=_blank}. -{* ../../docs_src/response_model/tutorial003_02.py hl[8,10:11] *} +{* ../../docs_src/response_model/tutorial003_02_py39.py hl[8,10:11] *} Este caso simples é tratado automaticamente pelo FastAPI porque a anotação do tipo de retorno é a classe (ou uma subclasse de) `Response`. @@ -193,7 +193,7 @@ E as ferramentas também ficarão felizes porque `RedirectResponse` e ​​`JSO Você também pode usar uma subclasse de `Response` na anotação de tipo: -{* ../../docs_src/response_model/tutorial003_03.py hl[8:9] *} +{* ../../docs_src/response_model/tutorial003_03_py39.py hl[8:9] *} Isso também funcionará porque `RedirectResponse` é uma subclasse de `Response`, e o FastAPI tratará automaticamente este caso simples. diff --git a/docs/pt/docs/tutorial/response-status-code.md b/docs/pt/docs/tutorial/response-status-code.md index 854bf57c9d..756c86dada 100644 --- a/docs/pt/docs/tutorial/response-status-code.md +++ b/docs/pt/docs/tutorial/response-status-code.md @@ -8,7 +8,7 @@ Da mesma forma que você pode especificar um modelo de resposta, você também p * `@app.delete()` * etc. -{* ../../docs_src/response_status_code/tutorial001.py hl[6] *} +{* ../../docs_src/response_status_code/tutorial001_py39.py hl[6] *} /// note | Nota @@ -74,7 +74,7 @@ Para saber mais sobre cada código de status e qual código serve para quê, ver Vamos ver o exemplo anterior novamente: -{* ../../docs_src/response_status_code/tutorial001.py hl[6] *} +{* ../../docs_src/response_status_code/tutorial001_py39.py hl[6] *} `201` é o código de status para "Criado". @@ -82,7 +82,7 @@ Mas você não precisa memorizar o que cada um desses códigos significa. Você pode usar as variáveis de conveniência de `fastapi.status`. -{* ../../docs_src/response_status_code/tutorial002.py hl[1,6] *} +{* ../../docs_src/response_status_code/tutorial002_py39.py hl[1,6] *} Eles são apenas uma conveniência, eles possuem o mesmo número, mas dessa forma você pode usar o preenchimento automático do editor para encontrá-los: diff --git a/docs/pt/docs/tutorial/static-files.md b/docs/pt/docs/tutorial/static-files.md index 13313a909e..04a02c7f96 100644 --- a/docs/pt/docs/tutorial/static-files.md +++ b/docs/pt/docs/tutorial/static-files.md @@ -7,7 +7,7 @@ Você pode servir arquivos estáticos automaticamente a partir de um diretório * Importe `StaticFiles`. * "Monte" uma instância de `StaticFiles()` em um path específico. -{* ../../docs_src/static_files/tutorial001.py hl[2,6] *} +{* ../../docs_src/static_files/tutorial001_py39.py hl[2,6] *} /// note | Detalhes Técnicos diff --git a/docs/pt/docs/tutorial/testing.md b/docs/pt/docs/tutorial/testing.md index 03f1981a3c..e56edcb8c2 100644 --- a/docs/pt/docs/tutorial/testing.md +++ b/docs/pt/docs/tutorial/testing.md @@ -30,7 +30,7 @@ Use o objeto `TestClient` da mesma forma que você faz com `httpx`. Escreva instruções `assert` simples com as expressões Python padrão que você precisa verificar (novamente, `pytest` padrão). -{* ../../docs_src/app_testing/tutorial001.py hl[2,12,15:18] *} +{* ../../docs_src/app_testing/tutorial001_py39.py hl[2,12,15:18] *} /// tip | Dica @@ -76,7 +76,7 @@ Digamos que você tenha uma estrutura de arquivo conforme descrito em [Aplicaç No arquivo `main.py` você tem sua aplicação **FastAPI**: -{* ../../docs_src/app_testing/main.py *} +{* ../../docs_src/app_testing/app_a_py39/main.py *} ### Arquivo de teste { #testing-file } @@ -92,7 +92,7 @@ Então você poderia ter um arquivo `test_main.py` com seus testes. Ele poderia Como esse arquivo está no mesmo pacote, você pode usar importações relativas para importar o objeto `app` do módulo `main` (`main.py`): -{* ../../docs_src/app_testing/test_main.py hl[3] *} +{* ../../docs_src/app_testing/app_a_py39/test_main.py hl[3] *} ...e ter o código para os testes como antes. diff --git a/docs/pt/llm-prompt.md b/docs/pt/llm-prompt.md index 01ce4143cb..2374070ced 100644 --- a/docs/pt/llm-prompt.md +++ b/docs/pt/llm-prompt.md @@ -47,7 +47,7 @@ For the next terms, use the following translations: * list (as in Python list): list * Machine Learning: Aprendizado de Máquina * media type: media type (do not translate to "tipo de mídia") -* non-Annotated: non-Annotated (do not translate non-Annotated when it comes after a Python version.e.g., “Python 3.8+ non-Annotated”) +* non-Annotated: non-Annotated (do not translate non-Annotated when it comes after a Python version.e.g., “Python 3.10+ non-Annotated”) * operation IDs: IDs de operação * path (as in URL path): path * path operation: operação de rota diff --git a/docs/ru/docs/advanced/additional-responses.md b/docs/ru/docs/advanced/additional-responses.md index 1fc3715e41..fca4f072da 100644 --- a/docs/ru/docs/advanced/additional-responses.md +++ b/docs/ru/docs/advanced/additional-responses.md @@ -26,7 +26,7 @@ Например, чтобы объявить ещё один ответ со статус-кодом `404` и Pydantic-моделью `Message`, можно написать: -{* ../../docs_src/additional_responses/tutorial001.py hl[18,22] *} +{* ../../docs_src/additional_responses/tutorial001_py39.py hl[18,22] *} /// note | Примечание @@ -203,7 +203,7 @@ А также ответ со статус-кодом `200`, который использует ваш `response_model`, но включает пользовательский `example`: -{* ../../docs_src/additional_responses/tutorial003.py hl[20:31] *} +{* ../../docs_src/additional_responses/tutorial003_py39.py hl[20:31] *} Всё это будет объединено и включено в ваш OpenAPI и отображено в документации API: diff --git a/docs/ru/docs/advanced/async-tests.md b/docs/ru/docs/advanced/async-tests.md index 5062bc52e7..e689704066 100644 --- a/docs/ru/docs/advanced/async-tests.md +++ b/docs/ru/docs/advanced/async-tests.md @@ -32,11 +32,11 @@ Файл `main.py`: -{* ../../docs_src/async_tests/main.py *} +{* ../../docs_src/async_tests/app_a_py39/main.py *} Файл `test_main.py` содержит тесты для `main.py`, теперь он может выглядеть так: -{* ../../docs_src/async_tests/test_main.py *} +{* ../../docs_src/async_tests/app_a_py39/test_main.py *} ## Запуск тестов { #run-it } @@ -56,7 +56,7 @@ $ pytest Маркер `@pytest.mark.anyio` говорит pytest, что тестовая функция должна быть вызвана асинхронно: -{* ../../docs_src/async_tests/test_main.py hl[7] *} +{* ../../docs_src/async_tests/app_a_py39/test_main.py hl[7] *} /// tip | Подсказка @@ -66,7 +66,7 @@ $ pytest Затем мы можем создать `AsyncClient` со ссылкой на приложение и посылать асинхронные запросы, используя `await`. -{* ../../docs_src/async_tests/test_main.py hl[9:12] *} +{* ../../docs_src/async_tests/app_a_py39/test_main.py hl[9:12] *} Это эквивалентно следующему: diff --git a/docs/ru/docs/advanced/behind-a-proxy.md b/docs/ru/docs/advanced/behind-a-proxy.md index 7119efe2dc..f78da01a09 100644 --- a/docs/ru/docs/advanced/behind-a-proxy.md +++ b/docs/ru/docs/advanced/behind-a-proxy.md @@ -44,7 +44,7 @@ $ fastapi run --forwarded-allow-ips="*" Например, вы объявили операцию пути `/items/`: -{* ../../docs_src/behind_a_proxy/tutorial001_01.py hl[6] *} +{* ../../docs_src/behind_a_proxy/tutorial001_01_py39.py hl[6] *} Если клиент обратится к `/items`, по умолчанию произойдёт редирект на `/items/`. @@ -115,7 +115,7 @@ sequenceDiagram Хотя весь ваш код написан с расчётом, что путь один — `/app`. -{* ../../docs_src/behind_a_proxy/tutorial001.py hl[6] *} +{* ../../docs_src/behind_a_proxy/tutorial001_py39.py hl[6] *} Прокси будет «обрезать» префикс пути на лету перед передачей запроса на сервер приложения (скорее всего Uvicorn, запущенный через FastAPI CLI), поддерживая у вашего приложения иллюзию, что его обслуживают по `/app`, чтобы вам не пришлось менять весь код и добавлять префикс `/api/v1`. @@ -193,7 +193,7 @@ $ fastapi run main.py --forwarded-allow-ips="*" --root-path /api/v1 Здесь мы добавляем его в сообщение лишь для демонстрации. -{* ../../docs_src/behind_a_proxy/tutorial001.py hl[8] *} +{* ../../docs_src/behind_a_proxy/tutorial001_py39.py hl[8] *} Затем, если вы запустите Uvicorn так: @@ -220,7 +220,7 @@ $ fastapi run main.py --forwarded-allow-ips="*" --root-path /api/v1 Если нет возможности передать опцию командной строки `--root-path` (или аналог), вы можете указать параметр `root_path` при создании приложения FastAPI: -{* ../../docs_src/behind_a_proxy/tutorial002.py hl[3] *} +{* ../../docs_src/behind_a_proxy/tutorial002_py39.py hl[3] *} Передача `root_path` в `FastAPI` эквивалентна опции командной строки `--root-path` для Uvicorn или Hypercorn. @@ -400,7 +400,7 @@ $ fastapi run main.py --forwarded-allow-ips="*" --root-path /api/v1 Например: -{* ../../docs_src/behind_a_proxy/tutorial003.py hl[4:7] *} +{* ../../docs_src/behind_a_proxy/tutorial003_py39.py hl[4:7] *} Будет сгенерирована схема OpenAPI примерно такая: @@ -455,7 +455,7 @@ $ fastapi run main.py --forwarded-allow-ips="*" --root-path /api/v1 Если вы не хотите, чтобы FastAPI добавлял автоматический сервер, используя `root_path`, укажите параметр `root_path_in_servers=False`: -{* ../../docs_src/behind_a_proxy/tutorial004.py hl[9] *} +{* ../../docs_src/behind_a_proxy/tutorial004_py39.py hl[9] *} и тогда этот сервер не будет добавлен в схему OpenAPI. diff --git a/docs/ru/docs/advanced/custom-response.md b/docs/ru/docs/advanced/custom-response.md index 2c238bd95b..49550b49ff 100644 --- a/docs/ru/docs/advanced/custom-response.md +++ b/docs/ru/docs/advanced/custom-response.md @@ -30,7 +30,7 @@ Но если вы уверены, что содержимое, которое вы возвращаете, **сериализуемо в JSON**, вы можете передать его напрямую в класс ответа и избежать дополнительных накладных расходов, которые FastAPI понёс бы, пропуская возвращаемое содержимое через `jsonable_encoder` перед передачей в класс ответа. -{* ../../docs_src/custom_response/tutorial001b.py hl[2,7] *} +{* ../../docs_src/custom_response/tutorial001b_py39.py hl[2,7] *} /// info | Информация @@ -55,7 +55,7 @@ - Импортируйте `HTMLResponse`. - Передайте `HTMLResponse` в параметр `response_class` вашего декоратора операции пути. -{* ../../docs_src/custom_response/tutorial002.py hl[2,7] *} +{* ../../docs_src/custom_response/tutorial002_py39.py hl[2,7] *} /// info | Информация @@ -73,7 +73,7 @@ Тот же пример сверху, возвращающий `HTMLResponse`, может выглядеть так: -{* ../../docs_src/custom_response/tutorial003.py hl[2,7,19] *} +{* ../../docs_src/custom_response/tutorial003_py39.py hl[2,7,19] *} /// warning | Предупреждение @@ -97,7 +97,7 @@ Например, это может быть что-то вроде: -{* ../../docs_src/custom_response/tutorial004.py hl[7,21,23] *} +{* ../../docs_src/custom_response/tutorial004_py39.py hl[7,21,23] *} В этом примере функция `generate_html_response()` уже генерирует и возвращает `Response` вместо возврата HTML в `str`. @@ -136,7 +136,7 @@ FastAPI (фактически Starlette) автоматически добавит заголовок Content-Length. Также будет добавлен заголовок Content-Type, основанный на `media_type` и с добавлением charset для текстовых типов. -{* ../../docs_src/response_directly/tutorial002.py hl[1,18] *} +{* ../../docs_src/response_directly/tutorial002_py39.py hl[1,18] *} ### `HTMLResponse` { #htmlresponse } @@ -146,7 +146,7 @@ FastAPI (фактически Starlette) автоматически добави Принимает текст или байты и возвращает ответ в виде простого текста. -{* ../../docs_src/custom_response/tutorial005.py hl[2,7,9] *} +{* ../../docs_src/custom_response/tutorial005_py39.py hl[2,7,9] *} ### `JSONResponse` { #jsonresponse } @@ -180,7 +180,7 @@ FastAPI (фактически Starlette) автоматически добави /// -{* ../../docs_src/custom_response/tutorial001.py hl[2,7] *} +{* ../../docs_src/custom_response/tutorial001_py39.py hl[2,7] *} /// tip | Совет @@ -194,13 +194,13 @@ FastAPI (фактически Starlette) автоматически добави Вы можете вернуть `RedirectResponse` напрямую: -{* ../../docs_src/custom_response/tutorial006.py hl[2,9] *} +{* ../../docs_src/custom_response/tutorial006_py39.py hl[2,9] *} --- Или можно использовать его в параметре `response_class`: -{* ../../docs_src/custom_response/tutorial006b.py hl[2,7,9] *} +{* ../../docs_src/custom_response/tutorial006b_py39.py hl[2,7,9] *} Если вы сделаете так, то сможете возвращать URL напрямую из своей функции-обработчика пути. @@ -210,13 +210,13 @@ FastAPI (фактически Starlette) автоматически добави Также вы можете использовать параметр `status_code` в сочетании с параметром `response_class`: -{* ../../docs_src/custom_response/tutorial006c.py hl[2,7,9] *} +{* ../../docs_src/custom_response/tutorial006c_py39.py hl[2,7,9] *} ### `StreamingResponse` { #streamingresponse } Принимает асинхронный генератор или обычный генератор/итератор и отправляет тело ответа потоково. -{* ../../docs_src/custom_response/tutorial007.py hl[2,14] *} +{* ../../docs_src/custom_response/tutorial007_py39.py hl[2,14] *} #### Использование `StreamingResponse` с файлоподобными объектами { #using-streamingresponse-with-file-like-objects } @@ -226,7 +226,7 @@ FastAPI (фактически Starlette) автоматически добави Это включает многие библиотеки для работы с облачным хранилищем, обработки видео и т.д. -{* ../../docs_src/custom_response/tutorial008.py hl[2,10:12,14] *} +{* ../../docs_src/custom_response/tutorial008_py39.py hl[2,10:12,14] *} 1. Это функция-генератор. Она является «функцией-генератором», потому что содержит оператор(ы) `yield` внутри. 2. Используя блок `with`, мы гарантируем, что файлоподобный объект будет закрыт после завершения работы функции-генератора. То есть после того, как она закончит отправку ответа. @@ -255,11 +255,11 @@ FastAPI (фактически Starlette) автоматически добави Файловые ответы будут содержать соответствующие заголовки `Content-Length`, `Last-Modified` и `ETag`. -{* ../../docs_src/custom_response/tutorial009.py hl[2,10] *} +{* ../../docs_src/custom_response/tutorial009_py39.py hl[2,10] *} Вы также можете использовать параметр `response_class`: -{* ../../docs_src/custom_response/tutorial009b.py hl[2,8,10] *} +{* ../../docs_src/custom_response/tutorial009b_py39.py hl[2,8,10] *} В этом случае вы можете возвращать путь к файлу напрямую из своей функции-обработчика пути. @@ -273,7 +273,7 @@ FastAPI (фактически Starlette) автоматически добави Вы могли бы создать `CustomORJSONResponse`. Главное, что вам нужно сделать — реализовать метод `Response.render(content)`, который возвращает содержимое как `bytes`: -{* ../../docs_src/custom_response/tutorial009c.py hl[9:14,17] *} +{* ../../docs_src/custom_response/tutorial009c_py39.py hl[9:14,17] *} Теперь вместо того, чтобы возвращать: @@ -299,7 +299,7 @@ FastAPI (фактически Starlette) автоматически добави В примере ниже **FastAPI** будет использовать `ORJSONResponse` по умолчанию во всех операциях пути вместо `JSONResponse`. -{* ../../docs_src/custom_response/tutorial010.py hl[2,4] *} +{* ../../docs_src/custom_response/tutorial010_py39.py hl[2,4] *} /// tip | Совет diff --git a/docs/ru/docs/advanced/events.md b/docs/ru/docs/advanced/events.md index 20d1df98a9..db73d9094e 100644 --- a/docs/ru/docs/advanced/events.md +++ b/docs/ru/docs/advanced/events.md @@ -30,7 +30,7 @@ Мы создаём асинхронную функцию `lifespan()` с `yield` примерно так: -{* ../../docs_src/events/tutorial003.py hl[16,19] *} +{* ../../docs_src/events/tutorial003_py39.py hl[16,19] *} Здесь мы симулируем дорогую операцию startup по загрузке модели, помещая (фиктивную) функцию модели в словарь с моделями Машинного обучения до `yield`. Этот код будет выполнен до того, как приложение начнет принимать запросы, во время startup. @@ -48,7 +48,7 @@ Первое, на что стоит обратить внимание, — мы определяем асинхронную функцию с `yield`. Это очень похоже на Зависимости с `yield`. -{* ../../docs_src/events/tutorial003.py hl[14:19] *} +{* ../../docs_src/events/tutorial003_py39.py hl[14:19] *} Первая часть функции, до `yield`, будет выполнена до запуска приложения. @@ -60,7 +60,7 @@ Это превращает функцию в «асинхронный менеджер контекста». -{* ../../docs_src/events/tutorial003.py hl[1,13] *} +{* ../../docs_src/events/tutorial003_py39.py hl[1,13] *} Менеджер контекста в Python — это то, что можно использовать в операторе `with`. Например, `open()` можно использовать как менеджер контекста: @@ -82,7 +82,7 @@ async with lifespan(app): Параметр `lifespan` приложения `FastAPI` принимает асинхронный менеджер контекста, поэтому мы можем передать ему наш новый асинхронный менеджер контекста `lifespan`. -{* ../../docs_src/events/tutorial003.py hl[22] *} +{* ../../docs_src/events/tutorial003_py39.py hl[22] *} ## Альтернативные события (устаревшие) { #alternative-events-deprecated } @@ -104,7 +104,7 @@ async with lifespan(app): Чтобы добавить функцию, которую нужно запустить до старта приложения, объявите её как обработчик события `"startup"`: -{* ../../docs_src/events/tutorial001.py hl[8] *} +{* ../../docs_src/events/tutorial001_py39.py hl[8] *} В этом случае функция-обработчик события `startup` инициализирует «базу данных» items (это просто `dict`) некоторыми значениями. @@ -116,7 +116,7 @@ async with lifespan(app): Чтобы добавить функцию, которую нужно запустить при завершении работы приложения, объявите её как обработчик события `"shutdown"`: -{* ../../docs_src/events/tutorial002.py hl[6] *} +{* ../../docs_src/events/tutorial002_py39.py hl[6] *} Здесь функция-обработчик события `shutdown` запишет строку текста `"Application shutdown"` в файл `log.txt`. diff --git a/docs/ru/docs/advanced/generate-clients.md b/docs/ru/docs/advanced/generate-clients.md index ee52412c6d..00bdd31fe8 100644 --- a/docs/ru/docs/advanced/generate-clients.md +++ b/docs/ru/docs/advanced/generate-clients.md @@ -167,7 +167,7 @@ FastAPI использует **уникальный ID** для каждой *о Мы можем скачать OpenAPI JSON в файл `openapi.json`, а затем **убрать этот префикс‑тег** таким скриптом: -{* ../../docs_src/generate_clients/tutorial004.py *} +{* ../../docs_src/generate_clients/tutorial004_py39.py *} //// tab | Node.js diff --git a/docs/ru/docs/advanced/middleware.md b/docs/ru/docs/advanced/middleware.md index 82c86b2317..5ebe010782 100644 --- a/docs/ru/docs/advanced/middleware.md +++ b/docs/ru/docs/advanced/middleware.md @@ -57,13 +57,13 @@ app.add_middleware(UnicornMiddleware, some_config="rainbow") Любой входящий запрос по `http` или `ws` будет перенаправлен на безопасную схему. -{* ../../docs_src/advanced_middleware/tutorial001.py hl[2,6] *} +{* ../../docs_src/advanced_middleware/tutorial001_py39.py hl[2,6] *} ## `TrustedHostMiddleware` { #trustedhostmiddleware } Гарантирует, что во всех входящих запросах корректно установлен `Host`‑заголовок, чтобы защититься от атак на HTTP‑заголовок Host. -{* ../../docs_src/advanced_middleware/tutorial002.py hl[2,6:8] *} +{* ../../docs_src/advanced_middleware/tutorial002_py39.py hl[2,6:8] *} Поддерживаются следующие аргументы: @@ -78,7 +78,7 @@ app.add_middleware(UnicornMiddleware, some_config="rainbow") Это middleware обрабатывает как обычные, так и потоковые ответы. -{* ../../docs_src/advanced_middleware/tutorial003.py hl[2,6] *} +{* ../../docs_src/advanced_middleware/tutorial003_py39.py hl[2,6] *} Поддерживаются следующие аргументы: diff --git a/docs/ru/docs/advanced/openapi-webhooks.md b/docs/ru/docs/advanced/openapi-webhooks.md index d38cf315f7..3a2b9fff74 100644 --- a/docs/ru/docs/advanced/openapi-webhooks.md +++ b/docs/ru/docs/advanced/openapi-webhooks.md @@ -32,7 +32,7 @@ При создании приложения на **FastAPI** есть атрибут `webhooks`, с помощью которого можно объявлять вебхуки так же, как вы объявляете операции пути (обработчики пути), например с `@app.webhooks.post()`. -{* ../../docs_src/openapi_webhooks/tutorial001.py hl[9:13,36:53] *} +{* ../../docs_src/openapi_webhooks/tutorial001_py39.py hl[9:13,36:53] *} Определенные вами вебхуки попадут в схему **OpenAPI** и в автоматический **интерфейс документации**. diff --git a/docs/ru/docs/advanced/path-operation-advanced-configuration.md b/docs/ru/docs/advanced/path-operation-advanced-configuration.md index 78a16a5583..eaf9ad0528 100644 --- a/docs/ru/docs/advanced/path-operation-advanced-configuration.md +++ b/docs/ru/docs/advanced/path-operation-advanced-configuration.md @@ -12,7 +12,7 @@ Нужно убедиться, что он уникален для каждой операции. -{* ../../docs_src/path_operation_advanced_configuration/tutorial001.py hl[6] *} +{* ../../docs_src/path_operation_advanced_configuration/tutorial001_py39.py hl[6] *} ### Использование имени функции-обработчика пути как operationId { #using-the-path-operation-function-name-as-the-operationid } @@ -20,7 +20,7 @@ Делать это следует после добавления всех *операций пути*. -{* ../../docs_src/path_operation_advanced_configuration/tutorial002.py hl[2, 12:21, 24] *} +{* ../../docs_src/path_operation_advanced_configuration/tutorial002_py39.py hl[2, 12:21, 24] *} /// tip | Совет @@ -40,7 +40,7 @@ Чтобы исключить *операцию пути* из генерируемой схемы OpenAPI (а значит, и из автоматической документации), используйте параметр `include_in_schema` и установите его в `False`: -{* ../../docs_src/path_operation_advanced_configuration/tutorial003.py hl[6] *} +{* ../../docs_src/path_operation_advanced_configuration/tutorial003_py39.py hl[6] *} ## Расширенное описание из docstring { #advanced-description-from-docstring } @@ -92,7 +92,7 @@ `openapi_extra` может пригодиться, например, чтобы объявить [Расширения OpenAPI](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#specificationExtensions): -{* ../../docs_src/path_operation_advanced_configuration/tutorial005.py hl[6] *} +{* ../../docs_src/path_operation_advanced_configuration/tutorial005_py39.py hl[6] *} Если вы откроете автоматическую документацию API, ваше расширение появится внизу страницы конкретной *операции пути*. @@ -139,7 +139,7 @@ Это можно сделать с помощью `openapi_extra`: -{* ../../docs_src/path_operation_advanced_configuration/tutorial006.py hl[19:36, 39:40] *} +{* ../../docs_src/path_operation_advanced_configuration/tutorial006_py39.py hl[19:36, 39:40] *} В этом примере мы не объявляли никакую Pydantic-модель. Фактически тело запроса даже не распарсено как JSON, оно читается напрямую как `bytes`, а функция `magic_data_reader()` будет отвечать за его парсинг каким-то способом. diff --git a/docs/ru/docs/advanced/response-change-status-code.md b/docs/ru/docs/advanced/response-change-status-code.md index e9e1c9470f..85d9050ffc 100644 --- a/docs/ru/docs/advanced/response-change-status-code.md +++ b/docs/ru/docs/advanced/response-change-status-code.md @@ -20,7 +20,7 @@ И затем вы можете установить `status_code` в этом *временном* объекте ответа. -{* ../../docs_src/response_change_status_code/tutorial001.py hl[1,9,12] *} +{* ../../docs_src/response_change_status_code/tutorial001_py39.py hl[1,9,12] *} После этого вы можете вернуть любой объект, который вам нужен, как обычно (`dict`, модель базы данных и т.д.). diff --git a/docs/ru/docs/advanced/response-cookies.md b/docs/ru/docs/advanced/response-cookies.md index 9319aba6e2..2872d6c0ad 100644 --- a/docs/ru/docs/advanced/response-cookies.md +++ b/docs/ru/docs/advanced/response-cookies.md @@ -6,7 +6,7 @@ Затем установить cookies в этом временном объекте ответа. -{* ../../docs_src/response_cookies/tutorial002.py hl[1, 8:9] *} +{* ../../docs_src/response_cookies/tutorial002_py39.py hl[1, 8:9] *} После этого можно вернуть любой объект, как и раньше (например, `dict`, объект модели базы данных и так далее). @@ -24,7 +24,7 @@ Затем установите cookies и верните этот объект: -{* ../../docs_src/response_cookies/tutorial001.py hl[10:12] *} +{* ../../docs_src/response_cookies/tutorial001_py39.py hl[10:12] *} /// tip | Совет diff --git a/docs/ru/docs/advanced/response-directly.md b/docs/ru/docs/advanced/response-directly.md index 3c10633e91..b452810714 100644 --- a/docs/ru/docs/advanced/response-directly.md +++ b/docs/ru/docs/advanced/response-directly.md @@ -54,7 +54,7 @@ Вы можете поместить ваш XML-контент в строку, поместить её в `Response` и вернуть: -{* ../../docs_src/response_directly/tutorial002.py hl[1,18] *} +{* ../../docs_src/response_directly/tutorial002_py39.py hl[1,18] *} ## Примечания { #notes } diff --git a/docs/ru/docs/advanced/response-headers.md b/docs/ru/docs/advanced/response-headers.md index 1c9360b31d..8f24f05b07 100644 --- a/docs/ru/docs/advanced/response-headers.md +++ b/docs/ru/docs/advanced/response-headers.md @@ -6,7 +6,7 @@ А затем вы можете устанавливать HTTP-заголовки в этом *временном* объекте ответа. -{* ../../docs_src/response_headers/tutorial002.py hl[1, 7:8] *} +{* ../../docs_src/response_headers/tutorial002_py39.py hl[1, 7:8] *} После этого вы можете вернуть любой нужный объект, как обычно (например, `dict`, модель из базы данных и т.д.). @@ -22,7 +22,7 @@ Создайте ответ, как описано в [Вернуть Response напрямую](response-directly.md){.internal-link target=_blank}, и передайте заголовки как дополнительный параметр: -{* ../../docs_src/response_headers/tutorial001.py hl[10:12] *} +{* ../../docs_src/response_headers/tutorial001_py39.py hl[10:12] *} /// note | Технические детали diff --git a/docs/ru/docs/advanced/settings.md b/docs/ru/docs/advanced/settings.md index 0ef46fb13c..b96ee44a3a 100644 --- a/docs/ru/docs/advanced/settings.md +++ b/docs/ru/docs/advanced/settings.md @@ -62,7 +62,7 @@ $ pip install "fastapi[all]" //// tab | Pydantic v2 -{* ../../docs_src/settings/tutorial001.py hl[2,5:8,11] *} +{* ../../docs_src/settings/tutorial001_py39.py hl[2,5:8,11] *} //// @@ -74,7 +74,7 @@ $ pip install "fastapi[all]" /// -{* ../../docs_src/settings/tutorial001_pv1.py hl[2,5:8,11] *} +{* ../../docs_src/settings/tutorial001_pv1_py39.py hl[2,5:8,11] *} //// @@ -92,7 +92,7 @@ $ pip install "fastapi[all]" Затем вы можете использовать новый объект `settings` в вашем приложении: -{* ../../docs_src/settings/tutorial001.py hl[18:20] *} +{* ../../docs_src/settings/tutorial001_py39.py hl[18:20] *} ### Запуск сервера { #run-the-server } @@ -126,11 +126,11 @@ $ ADMIN_EMAIL="deadpool@example.com" APP_NAME="ChimichangApp" fastapi run main.p Например, у вас может быть файл `config.py` со следующим содержимым: -{* ../../docs_src/settings/app01/config.py *} +{* ../../docs_src/settings/app01_py39/config.py *} А затем использовать его в файле `main.py`: -{* ../../docs_src/settings/app01/main.py hl[3,11:13] *} +{* ../../docs_src/settings/app01_py39/main.py hl[3,11:13] *} /// tip | Совет diff --git a/docs/ru/docs/advanced/sub-applications.md b/docs/ru/docs/advanced/sub-applications.md index 3464f17040..fa5a683f45 100644 --- a/docs/ru/docs/advanced/sub-applications.md +++ b/docs/ru/docs/advanced/sub-applications.md @@ -10,7 +10,7 @@ Сначала создайте основное, верхнего уровня, приложение **FastAPI** и его *операции пути*: -{* ../../docs_src/sub_applications/tutorial001.py hl[3, 6:8] *} +{* ../../docs_src/sub_applications/tutorial001_py39.py hl[3, 6:8] *} ### Подприложение { #sub-application } @@ -18,7 +18,7 @@ Это подприложение — обычное стандартное приложение FastAPI, но именно оно будет «смонтировано»: -{* ../../docs_src/sub_applications/tutorial001.py hl[11, 14:16] *} +{* ../../docs_src/sub_applications/tutorial001_py39.py hl[11, 14:16] *} ### Смонтируйте подприложение { #mount-the-sub-application } @@ -26,7 +26,7 @@ В этом случае оно будет смонтировано по пути `/subapi`: -{* ../../docs_src/sub_applications/tutorial001.py hl[11, 19] *} +{* ../../docs_src/sub_applications/tutorial001_py39.py hl[11, 19] *} ### Проверьте автоматическую документацию API { #check-the-automatic-api-docs } diff --git a/docs/ru/docs/advanced/templates.md b/docs/ru/docs/advanced/templates.md index 204e887605..460e2e4660 100644 --- a/docs/ru/docs/advanced/templates.md +++ b/docs/ru/docs/advanced/templates.md @@ -27,7 +27,7 @@ $ pip install jinja2 - Объявите параметр `Request` в *операции пути*, которая будет возвращать шаблон. - Используйте созданный `templates`, чтобы отрендерить и вернуть `TemplateResponse`; передайте имя шаблона, объект `request` и словарь «context» с парами ключ-значение для использования внутри шаблона Jinja2. -{* ../../docs_src/templates/tutorial001.py hl[4,11,15:18] *} +{* ../../docs_src/templates/tutorial001_py39.py hl[4,11,15:18] *} /// note | Примечание diff --git a/docs/ru/docs/advanced/testing-events.md b/docs/ru/docs/advanced/testing-events.md index e0ec774399..82caea845b 100644 --- a/docs/ru/docs/advanced/testing-events.md +++ b/docs/ru/docs/advanced/testing-events.md @@ -2,11 +2,11 @@ Если вам нужно, чтобы `lifespan` выполнялся в ваших тестах, вы можете использовать `TestClient` вместе с оператором `with`: -{* ../../docs_src/app_testing/tutorial004.py hl[9:15,18,27:28,30:32,41:43] *} +{* ../../docs_src/app_testing/tutorial004_py39.py hl[9:15,18,27:28,30:32,41:43] *} Вы можете узнать больше подробностей в статье [Запуск lifespan в тестах на официальном сайте документации Starlette.](https://www.starlette.dev/lifespan/#running-lifespan-in-tests) Для устаревших событий `startup` и `shutdown` вы можете использовать `TestClient` следующим образом: -{* ../../docs_src/app_testing/tutorial003.py hl[9:12,20:24] *} +{* ../../docs_src/app_testing/tutorial003_py39.py hl[9:12,20:24] *} diff --git a/docs/ru/docs/advanced/testing-websockets.md b/docs/ru/docs/advanced/testing-websockets.md index e840a03f28..b6626679e4 100644 --- a/docs/ru/docs/advanced/testing-websockets.md +++ b/docs/ru/docs/advanced/testing-websockets.md @@ -4,7 +4,7 @@ Для этого используйте `TestClient` с менеджером контекста `with`, подключаясь к WebSocket: -{* ../../docs_src/app_testing/tutorial002.py hl[27:31] *} +{* ../../docs_src/app_testing/tutorial002_py39.py hl[27:31] *} /// note | Примечание diff --git a/docs/ru/docs/advanced/using-request-directly.md b/docs/ru/docs/advanced/using-request-directly.md index b922216105..cdf500c0e2 100644 --- a/docs/ru/docs/advanced/using-request-directly.md +++ b/docs/ru/docs/advanced/using-request-directly.md @@ -29,7 +29,7 @@ Для этого нужно обратиться к запросу напрямую. -{* ../../docs_src/using_request_directly/tutorial001.py hl[1,7:8] *} +{* ../../docs_src/using_request_directly/tutorial001_py39.py hl[1,7:8] *} Если объявить параметр *функции-обработчика пути* с типом `Request`, **FastAPI** поймёт, что нужно передать объект `Request` в этот параметр. diff --git a/docs/ru/docs/advanced/websockets.md b/docs/ru/docs/advanced/websockets.md index f26185bea5..fa5e4738eb 100644 --- a/docs/ru/docs/advanced/websockets.md +++ b/docs/ru/docs/advanced/websockets.md @@ -38,13 +38,13 @@ $ pip install websockets Для примера нам нужен наиболее простой способ, который позволит сосредоточиться на серверной части веб‑сокетов и получить рабочий код: -{* ../../docs_src/websockets/tutorial001.py hl[2,6:38,41:43] *} +{* ../../docs_src/websockets/tutorial001_py39.py hl[2,6:38,41:43] *} ## Создание `websocket` { #create-a-websocket } Создайте `websocket` в своем **FastAPI** приложении: -{* ../../docs_src/websockets/tutorial001.py hl[1,46:47] *} +{* ../../docs_src/websockets/tutorial001_py39.py hl[1,46:47] *} /// note | Технические детали @@ -58,7 +58,7 @@ $ pip install websockets Через эндпоинт веб-сокета вы можете получать и отправлять сообщения. -{* ../../docs_src/websockets/tutorial001.py hl[48:52] *} +{* ../../docs_src/websockets/tutorial001_py39.py hl[48:52] *} Вы можете получать и отправлять двоичные, текстовые и JSON данные. diff --git a/docs/ru/docs/advanced/wsgi.md b/docs/ru/docs/advanced/wsgi.md index 1c5bf0a626..64d7c7a289 100644 --- a/docs/ru/docs/advanced/wsgi.md +++ b/docs/ru/docs/advanced/wsgi.md @@ -12,7 +12,7 @@ После этого смонтируйте его на путь. -{* ../../docs_src/wsgi/tutorial001.py hl[2:3,3] *} +{* ../../docs_src/wsgi/tutorial001_py39.py hl[2:3,3] *} ## Проверьте { #check-it } diff --git a/docs/ru/docs/how-to/conditional-openapi.md b/docs/ru/docs/how-to/conditional-openapi.md index dc987ae26b..d0845b91e2 100644 --- a/docs/ru/docs/how-to/conditional-openapi.md +++ b/docs/ru/docs/how-to/conditional-openapi.md @@ -29,7 +29,7 @@ Например: -{* ../../docs_src/conditional_openapi/tutorial001.py hl[6,11] *} +{* ../../docs_src/conditional_openapi/tutorial001_py39.py hl[6,11] *} Здесь мы объявляем настройку `openapi_url` с тем же значением по умолчанию — `"/openapi.json"`. diff --git a/docs/ru/docs/how-to/configure-swagger-ui.md b/docs/ru/docs/how-to/configure-swagger-ui.md index 9d104423d7..b3b1c1ba62 100644 --- a/docs/ru/docs/how-to/configure-swagger-ui.md +++ b/docs/ru/docs/how-to/configure-swagger-ui.md @@ -18,7 +18,7 @@ FastAPI преобразует эти настройки в **JSON**, чтобы Но вы можете отключить её, установив `syntaxHighlight` в `False`: -{* ../../docs_src/configure_swagger_ui/tutorial001.py hl[3] *} +{* ../../docs_src/configure_swagger_ui/tutorial001_py39.py hl[3] *} …и после этого Swagger UI больше не будет показывать подсветку синтаксиса: @@ -28,7 +28,7 @@ FastAPI преобразует эти настройки в **JSON**, чтобы Аналогично вы можете задать тему подсветки синтаксиса с ключом "syntaxHighlight.theme" (обратите внимание, что посередине стоит точка): -{* ../../docs_src/configure_swagger_ui/tutorial002.py hl[3] *} +{* ../../docs_src/configure_swagger_ui/tutorial002_py39.py hl[3] *} Эта настройка изменит цветовую тему подсветки синтаксиса: @@ -46,7 +46,7 @@ FastAPI включает некоторые параметры конфигур Например, чтобы отключить `deepLinking`, можно передать такие настройки в `swagger_ui_parameters`: -{* ../../docs_src/configure_swagger_ui/tutorial003.py hl[3] *} +{* ../../docs_src/configure_swagger_ui/tutorial003_py39.py hl[3] *} ## Другие параметры Swagger UI { #other-swagger-ui-parameters } diff --git a/docs/ru/docs/how-to/custom-docs-ui-assets.md b/docs/ru/docs/how-to/custom-docs-ui-assets.md index c07a9695b9..f524911e65 100644 --- a/docs/ru/docs/how-to/custom-docs-ui-assets.md +++ b/docs/ru/docs/how-to/custom-docs-ui-assets.md @@ -18,7 +18,7 @@ Чтобы отключить её, установите их URL в значение `None` при создании вашего приложения `FastAPI`: -{* ../../docs_src/custom_docs_ui/tutorial001.py hl[8] *} +{* ../../docs_src/custom_docs_ui/tutorial001_py39.py hl[8] *} ### Подключить пользовательскую документацию { #include-the-custom-docs } @@ -34,7 +34,7 @@ Аналогично и для ReDoc... -{* ../../docs_src/custom_docs_ui/tutorial001.py hl[2:6,11:19,22:24,27:33] *} +{* ../../docs_src/custom_docs_ui/tutorial001_py39.py hl[2:6,11:19,22:24,27:33] *} /// tip | Совет @@ -50,7 +50,7 @@ Swagger UI сделает это за вас «за кулисами», но д Чтобы убедиться, что всё работает, создайте *операцию пути*: -{* ../../docs_src/custom_docs_ui/tutorial001.py hl[36:38] *} +{* ../../docs_src/custom_docs_ui/tutorial001_py39.py hl[36:38] *} ### Тестирование { #test-it } @@ -118,7 +118,7 @@ Swagger UI сделает это за вас «за кулисами», но д * Импортируйте `StaticFiles`. * Смонтируйте экземпляр `StaticFiles()` в определённый путь. -{* ../../docs_src/custom_docs_ui/tutorial002.py hl[7,11] *} +{* ../../docs_src/custom_docs_ui/tutorial002_py39.py hl[7,11] *} ### Протестируйте статические файлы { #test-the-static-files } @@ -144,7 +144,7 @@ Swagger UI сделает это за вас «за кулисами», но д Чтобы отключить её, установите их URL в значение `None` при создании вашего приложения `FastAPI`: -{* ../../docs_src/custom_docs_ui/tutorial002.py hl[9] *} +{* ../../docs_src/custom_docs_ui/tutorial002_py39.py hl[9] *} ### Подключить пользовательскую документацию со статическими файлами { #include-the-custom-docs-for-static-files } @@ -160,7 +160,7 @@ Swagger UI сделает это за вас «за кулисами», но д Аналогично и для ReDoc... -{* ../../docs_src/custom_docs_ui/tutorial002.py hl[2:6,14:22,25:27,30:36] *} +{* ../../docs_src/custom_docs_ui/tutorial002_py39.py hl[2:6,14:22,25:27,30:36] *} /// tip | Совет @@ -176,7 +176,7 @@ Swagger UI сделает это за вас «за кулисами», но д Чтобы убедиться, что всё работает, создайте *операцию пути*: -{* ../../docs_src/custom_docs_ui/tutorial002.py hl[39:41] *} +{* ../../docs_src/custom_docs_ui/tutorial002_py39.py hl[39:41] *} ### Тестирование UI со статическими файлами { #test-static-files-ui } diff --git a/docs/ru/docs/how-to/extending-openapi.md b/docs/ru/docs/how-to/extending-openapi.md index 2897fb89ba..1d69cbdb3a 100644 --- a/docs/ru/docs/how-to/extending-openapi.md +++ b/docs/ru/docs/how-to/extending-openapi.md @@ -43,19 +43,19 @@ Сначала напишите приложение **FastAPI** как обычно: -{* ../../docs_src/extending_openapi/tutorial001.py hl[1,4,7:9] *} +{* ../../docs_src/extending_openapi/tutorial001_py39.py hl[1,4,7:9] *} ### Сгенерируйте схему OpenAPI { #generate-the-openapi-schema } Затем используйте ту же вспомогательную функцию для генерации схемы OpenAPI внутри функции `custom_openapi()`: -{* ../../docs_src/extending_openapi/tutorial001.py hl[2,15:21] *} +{* ../../docs_src/extending_openapi/tutorial001_py39.py hl[2,15:21] *} ### Измените схему OpenAPI { #modify-the-openapi-schema } Теперь можно добавить расширение ReDoc, добавив кастомный `x-logo` в «объект» `info` в схеме OpenAPI: -{* ../../docs_src/extending_openapi/tutorial001.py hl[22:24] *} +{* ../../docs_src/extending_openapi/tutorial001_py39.py hl[22:24] *} ### Кэшируйте схему OpenAPI { #cache-the-openapi-schema } @@ -65,13 +65,13 @@ Она будет создана один раз, а затем тот же кэшированный вариант будет использоваться для последующих запросов. -{* ../../docs_src/extending_openapi/tutorial001.py hl[13:14,25:26] *} +{* ../../docs_src/extending_openapi/tutorial001_py39.py hl[13:14,25:26] *} ### Переопределите метод { #override-the-method } Теперь вы можете заменить метод `.openapi()` на вашу новую функцию. -{* ../../docs_src/extending_openapi/tutorial001.py hl[29] *} +{* ../../docs_src/extending_openapi/tutorial001_py39.py hl[29] *} ### Проверьте { #check-it } diff --git a/docs/ru/docs/how-to/graphql.md b/docs/ru/docs/how-to/graphql.md index 9ed6d95ca1..97278069ad 100644 --- a/docs/ru/docs/how-to/graphql.md +++ b/docs/ru/docs/how-to/graphql.md @@ -35,7 +35,7 @@ Вот небольшой пример того, как можно интегрировать Strawberry с FastAPI: -{* ../../docs_src/graphql/tutorial001.py hl[3,22,25] *} +{* ../../docs_src/graphql/tutorial001_py39.py hl[3,22,25] *} Подробнее о Strawberry можно узнать в документации Strawberry. diff --git a/docs/ru/docs/python-types.md b/docs/ru/docs/python-types.md index 84a901f547..ae4a1e2b79 100644 --- a/docs/ru/docs/python-types.md +++ b/docs/ru/docs/python-types.md @@ -22,7 +22,7 @@ Python поддерживает необязательные «подсказк Давайте начнем с простого примера: -{* ../../docs_src/python_types/tutorial001.py *} +{* ../../docs_src/python_types/tutorial001_py39.py *} Вызов этой программы выводит: @@ -36,7 +36,7 @@ John Doe * Преобразует первую букву каждого значения в верхний регистр с помощью `title()`. * Соединяет их пробелом посередине. -{* ../../docs_src/python_types/tutorial001.py hl[2] *} +{* ../../docs_src/python_types/tutorial001_py39.py hl[2] *} ### Отредактируем пример { #edit-it } @@ -78,7 +78,7 @@ John Doe Это и есть «подсказки типов»: -{* ../../docs_src/python_types/tutorial002.py hl[1] *} +{* ../../docs_src/python_types/tutorial002_py39.py hl[1] *} Это не то же самое, что объявление значений по умолчанию, как, например: @@ -106,7 +106,7 @@ John Doe Посмотрите на эту функцию — у неё уже есть подсказки типов: -{* ../../docs_src/python_types/tutorial003.py hl[1] *} +{* ../../docs_src/python_types/tutorial003_py39.py hl[1] *} Так как редактор кода знает типы переменных, вы получаете не только автозавершение, но и проверки ошибок: @@ -114,7 +114,7 @@ John Doe Теперь вы знаете, что нужно исправить — преобразовать `age` в строку с помощью `str(age)`: -{* ../../docs_src/python_types/tutorial004.py hl[2] *} +{* ../../docs_src/python_types/tutorial004_py39.py hl[2] *} ## Объявление типов { #declaring-types } @@ -133,7 +133,7 @@ John Doe * `bool` * `bytes` -{* ../../docs_src/python_types/tutorial005.py hl[1] *} +{* ../../docs_src/python_types/tutorial005_py39.py hl[1] *} ### Generic-типы с параметрами типов { #generic-types-with-type-parameters } @@ -161,56 +161,24 @@ John Doe Например, давайте определим переменную как `list` из `str`. -//// tab | Python 3.9+ - Объявите переменную с тем же синтаксисом двоеточия (`:`). В качестве типа укажите `list`. Так как список — это тип, содержащий внутренние типы, укажите их в квадратных скобках: -```Python hl_lines="1" -{!> ../../docs_src/python_types/tutorial006_py39.py!} -``` - -//// - -//// tab | Python 3.8+ - -Из `typing` импортируйте `List` (с заглавной `L`): - -```Python hl_lines="1" -{!> ../../docs_src/python_types/tutorial006.py!} -``` - -Объявите переменную с тем же синтаксисом двоеточия (`:`). - -В качестве типа используйте `List`, который вы импортировали из `typing`. - -Так как список — это тип, содержащий внутренние типы, укажите их в квадратных скобках: - -```Python hl_lines="4" -{!> ../../docs_src/python_types/tutorial006.py!} -``` - -//// +{* ../../docs_src/python_types/tutorial006_py39.py hl[1] *} /// info | Информация Эти внутренние типы в квадратных скобках называются «параметрами типов». -В данном случае `str` — это параметр типа, передаваемый в `List` (или `list` в Python 3.9 и выше). +В данном случае `str` — это параметр типа, передаваемый в `list`. /// Это означает: «переменная `items` — это `list`, и каждый элемент этого списка — `str`». -/// tip | Совет - -Если вы используете Python 3.9 или выше, вам не нужно импортировать `List` из `typing`, можно использовать обычный встроенный тип `list`. - -/// - Таким образом, ваш редактор кода сможет помогать даже при обработке элементов списка: @@ -225,21 +193,7 @@ John Doe Аналогично вы бы объявили `tuple` и `set`: -//// tab | Python 3.9+ - -```Python hl_lines="1" -{!> ../../docs_src/python_types/tutorial007_py39.py!} -``` - -//// - -//// tab | Python 3.8+ - -```Python hl_lines="1 4" -{!> ../../docs_src/python_types/tutorial007.py!} -``` - -//// +{* ../../docs_src/python_types/tutorial007_py39.py hl[1] *} Это означает: @@ -254,21 +208,7 @@ John Doe Второй параметр типа — для значений `dict`: -//// tab | Python 3.9+ - -```Python hl_lines="1" -{!> ../../docs_src/python_types/tutorial008_py39.py!} -``` - -//// - -//// tab | Python 3.8+ - -```Python hl_lines="1 4" -{!> ../../docs_src/python_types/tutorial008.py!} -``` - -//// +{* ../../docs_src/python_types/tutorial008_py39.py hl[1] *} Это означает: @@ -292,10 +232,10 @@ John Doe //// -//// tab | Python 3.8+ +//// tab | Python 3.9+ ```Python hl_lines="1 4" -{!> ../../docs_src/python_types/tutorial008b.py!} +{!> ../../docs_src/python_types/tutorial008b_py39.py!} ``` //// @@ -309,7 +249,7 @@ John Doe В Python 3.6 и выше (включая Python 3.10) это можно объявить, импортировав и используя `Optional` из модуля `typing`. ```Python hl_lines="1 4" -{!../../docs_src/python_types/tutorial009.py!} +{!../../docs_src/python_types/tutorial009_py39.py!} ``` Использование `Optional[str]` вместо просто `str` позволит редактору кода помочь вам обнаружить ошибки, когда вы предполагаете, что значение всегда `str`, хотя на самом деле оно может быть и `None`. @@ -326,18 +266,18 @@ John Doe //// -//// tab | Python 3.8+ +//// tab | Python 3.9+ ```Python hl_lines="1 4" -{!> ../../docs_src/python_types/tutorial009.py!} +{!> ../../docs_src/python_types/tutorial009_py39.py!} ``` //// -//// tab | Python 3.8+ альтернативный вариант +//// tab | Python 3.9+ альтернативный вариант ```Python hl_lines="1 4" -{!> ../../docs_src/python_types/tutorial009b.py!} +{!> ../../docs_src/python_types/tutorial009b_py39.py!} ``` //// @@ -357,7 +297,7 @@ John Doe В качестве примера возьмём эту функцию: -{* ../../docs_src/python_types/tutorial009c.py hl[1,4] *} +{* ../../docs_src/python_types/tutorial009c_py39.py hl[1,4] *} Параметр `name` определён как `Optional[str]`, но он **не необязательный** — вы не можете вызвать функцию без этого параметра: @@ -390,10 +330,10 @@ say_hi(name=None) # Это работает, None допустим 🎉 * `set` * `dict` -И, как и в Python 3.8, из модуля `typing`: +И, как и в предыдущих версиях Python, из модуля `typing`: * `Union` -* `Optional` (так же, как в Python 3.8) +* `Optional` * ...и другие. В Python 3.10, как альтернативу generics `Union` и `Optional`, можно использовать вертикальную черту (`|`) для объявления объединений типов — это гораздо лучше и проще. @@ -409,7 +349,7 @@ say_hi(name=None) # Это работает, None допустим 🎉 * `set` * `dict` -И, как и в Python 3.8, из модуля `typing`: +И generics из модуля `typing`: * `Union` * `Optional` @@ -417,29 +357,17 @@ say_hi(name=None) # Это работает, None допустим 🎉 //// -//// tab | Python 3.8+ - -* `List` -* `Tuple` -* `Set` -* `Dict` -* `Union` -* `Optional` -* ...и другие. - -//// - ### Классы как типы { #classes-as-types } Вы также можете объявлять класс как тип переменной. Допустим, у вас есть класс `Person` с именем: -{* ../../docs_src/python_types/tutorial010.py hl[1:3] *} +{* ../../docs_src/python_types/tutorial010_py39.py hl[1:3] *} Тогда вы можете объявить переменную типа `Person`: -{* ../../docs_src/python_types/tutorial010.py hl[6] *} +{* ../../docs_src/python_types/tutorial010_py39.py hl[6] *} И снова вы получите полную поддержку редактора кода: @@ -463,29 +391,7 @@ say_hi(name=None) # Это работает, None допустим 🎉 Пример из официальной документации Pydantic: -//// tab | Python 3.10+ - -```Python -{!> ../../docs_src/python_types/tutorial011_py310.py!} -``` - -//// - -//// tab | Python 3.9+ - -```Python -{!> ../../docs_src/python_types/tutorial011_py39.py!} -``` - -//// - -//// tab | Python 3.8+ - -```Python -{!> ../../docs_src/python_types/tutorial011.py!} -``` - -//// +{* ../../docs_src/python_types/tutorial011_py310.py *} /// info | Информация @@ -507,27 +413,9 @@ say_hi(name=None) # Это работает, None допустим 🎉 В Python также есть возможность добавлять **дополнительные метаданные** к подсказкам типов с помощью `Annotated`. -//// tab | Python 3.9+ +Начиная с Python 3.9, `Annotated` входит в стандартную библиотеку, поэтому вы можете импортировать его из `typing`. -В Python 3.9 `Annotated` входит в стандартную библиотеку, поэтому вы можете импортировать его из `typing`. - -```Python hl_lines="1 4" -{!> ../../docs_src/python_types/tutorial013_py39.py!} -``` - -//// - -//// tab | Python 3.8+ - -В версиях ниже Python 3.9 импортируйте `Annotated` из `typing_extensions`. - -Он уже будет установлен вместе с **FastAPI**. - -```Python hl_lines="1 4" -{!> ../../docs_src/python_types/tutorial013.py!} -``` - -//// +{* ../../docs_src/python_types/tutorial013_py39.py hl[1,4] *} Сам Python ничего не делает с `Annotated`. А для редакторов кода и других инструментов тип по-прежнему `str`. @@ -558,7 +446,7 @@ say_hi(name=None) # Это работает, None допустим 🎉 ...и **FastAPI** использует эти же объявления для: -* **Определения требований**: из path-параметров, query-параметров, HTTP-заголовков, тел запросов, зависимостей и т.д. +* **Определения требований**: из path-параметров пути запроса, query-параметров, HTTP-заголовков, тел запросов, зависимостей и т.д. * **Преобразования данных**: из HTTP-запроса к требуемому типу. * **Валидации данных**: приходящих с каждого HTTP-запроса: * Генерации **автоматических ошибок**, возвращаемых клиенту, когда данные некорректны. diff --git a/docs/ru/docs/tutorial/background-tasks.md b/docs/ru/docs/tutorial/background-tasks.md index 1ed8522d69..8d7b7442f9 100644 --- a/docs/ru/docs/tutorial/background-tasks.md +++ b/docs/ru/docs/tutorial/background-tasks.md @@ -15,7 +15,7 @@ Сначала импортируйте `BackgroundTasks` и объявите параметр в вашей функции‑обработчике пути с типом `BackgroundTasks`: -{* ../../docs_src/background_tasks/tutorial001.py hl[1,13] *} +{* ../../docs_src/background_tasks/tutorial001_py39.py hl[1,13] *} **FastAPI** создаст объект типа `BackgroundTasks` для вас и передаст его через этот параметр. @@ -31,13 +31,13 @@ Так как операция записи не использует `async` и `await`, мы определим функцию как обычную `def`: -{* ../../docs_src/background_tasks/tutorial001.py hl[6:9] *} +{* ../../docs_src/background_tasks/tutorial001_py39.py hl[6:9] *} ## Добавление фоновой задачи { #add-the-background-task } Внутри вашей функции‑обработчика пути передайте функцию задачи объекту фоновых задач методом `.add_task()`: -{* ../../docs_src/background_tasks/tutorial001.py hl[14] *} +{* ../../docs_src/background_tasks/tutorial001_py39.py hl[14] *} `.add_task()` принимает следующие аргументы: diff --git a/docs/ru/docs/tutorial/body-nested-models.md b/docs/ru/docs/tutorial/body-nested-models.md index 5bb5abbe63..4c914b97f0 100644 --- a/docs/ru/docs/tutorial/body-nested-models.md +++ b/docs/ru/docs/tutorial/body-nested-models.md @@ -14,35 +14,14 @@ В Python есть специальный способ объявлять списки с внутренними типами, или «параметрами типа»: -### Импортируйте `List` из модуля typing { #import-typings-list } - -В Python 3.9 и выше вы можете использовать стандартный тип `list` для объявления аннотаций типов, как мы увидим ниже. 💡 - -Но в версиях Python до 3.9 (начиная с 3.6) сначала вам необходимо импортировать `List` из стандартного модуля `typing`: - -{* ../../docs_src/body_nested_models/tutorial002.py hl[1] *} - ### Объявите `list` с параметром типа { #declare-a-list-with-a-type-parameter } -Для объявления типов, у которых есть параметры типа (внутренние типы), таких как `list`, `dict`, `tuple`: - -* Если у вас Python версии ниже 3.9, импортируйте их аналоги из модуля `typing` -* Передайте внутренний(ие) тип(ы) как «параметры типа», используя квадратные скобки: `[` и `]` - -В Python 3.9 это будет: +Для объявления типов, у которых есть параметры типа (внутренние типы), таких как `list`, `dict`, `tuple`, передайте внутренний(ие) тип(ы) как «параметры типа», используя квадратные скобки: `[` и `]` ```Python my_list: list[str] ``` -В версиях Python до 3.9 это будет: - -```Python -from typing import List - -my_list: List[str] -``` - Это всё стандартный синтаксис Python для объявления типов. Используйте этот же стандартный синтаксис для атрибутов модели с внутренними типами. @@ -107,7 +86,7 @@ my_list: List[str] Ещё раз: сделав такое объявление, с помощью **FastAPI** вы получите: -* Поддержку редактора кода (автозавершение и т. д.), даже для вложенных моделей +* Поддержку редактора кода (автозавершение и т.д.), даже для вложенных моделей * Преобразование данных * Валидацию данных * Автоматическую документацию @@ -178,12 +157,6 @@ my_list: List[str] Если верхний уровень значения тела JSON-объекта представляет собой JSON `array` (в Python — `list`), вы можете объявить тип в параметре функции, так же как в моделях Pydantic: -```Python -images: List[Image] -``` - -или в Python 3.9 и выше: - ```Python images: list[Image] ``` diff --git a/docs/ru/docs/tutorial/body.md b/docs/ru/docs/tutorial/body.md index 16ff6466c1..b61f3e7a09 100644 --- a/docs/ru/docs/tutorial/body.md +++ b/docs/ru/docs/tutorial/body.md @@ -161,7 +161,7 @@ JSON Schema ваших моделей будет частью сгенериро FastAPI понимает, что значение `q` не является обязательным из-за значения по умолчанию `= None`. -Аннотации типов `str | None` (Python 3.10+) или `Union[str, None]` (Python 3.8+) не используются FastAPI для определения обязательности; он узнает, что параметр не обязателен, потому что у него есть значение по умолчанию `= None`. +Аннотации типов `str | None` (Python 3.10+) или `Union[str, None]` (Python 3.9+) не используются FastAPI для определения обязательности; он узнает, что параметр не обязателен, потому что у него есть значение по умолчанию `= None`. Но добавление аннотаций типов позволит вашему редактору кода лучше вас поддерживать и обнаруживать ошибки. diff --git a/docs/ru/docs/tutorial/cors.md b/docs/ru/docs/tutorial/cors.md index b0704351a9..d09a31e2c3 100644 --- a/docs/ru/docs/tutorial/cors.md +++ b/docs/ru/docs/tutorial/cors.md @@ -46,7 +46,7 @@ * Отдельных HTTP-методов (`POST`, `PUT`) или всех вместе, используя `"*"`. * Отдельных HTTP-заголовков или всех вместе, используя `"*"`. -{* ../../docs_src/cors/tutorial001.py hl[2,6:11,13:19] *} +{* ../../docs_src/cors/tutorial001_py39.py hl[2,6:11,13:19] *} `CORSMiddleware` использует "запрещающие" значения по умолчанию, поэтому вам нужно явным образом разрешить использование отдельных источников, методов или заголовков, чтобы браузеры могли использовать их в кросс-доменном контексте. diff --git a/docs/ru/docs/tutorial/debugging.md b/docs/ru/docs/tutorial/debugging.md index a5340af089..51955835e6 100644 --- a/docs/ru/docs/tutorial/debugging.md +++ b/docs/ru/docs/tutorial/debugging.md @@ -6,7 +6,7 @@ В вашем FastAPI приложении, импортируйте и вызовите `uvicorn` напрямую: -{* ../../docs_src/debugging/tutorial001.py hl[1,15] *} +{* ../../docs_src/debugging/tutorial001_py39.py hl[1,15] *} ### Описание `__name__ == "__main__"` { #about-name-main } diff --git a/docs/ru/docs/tutorial/dependencies/classes-as-dependencies.md b/docs/ru/docs/tutorial/dependencies/classes-as-dependencies.md index ec7770d960..a38e885d43 100644 --- a/docs/ru/docs/tutorial/dependencies/classes-as-dependencies.md +++ b/docs/ru/docs/tutorial/dependencies/classes-as-dependencies.md @@ -101,7 +101,7 @@ fluffy = Cat(name="Mr Fluffy") Обратите внимание, что в приведенном выше коде мы два раза пишем `CommonQueryParams`: -//// tab | Python 3.8+ +//// tab | Python 3.9+ ```Python commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)] @@ -109,7 +109,7 @@ commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)] //// -//// tab | Python 3.8+ non-Annotated +//// tab | Python 3.9+ non-Annotated /// tip | Подсказка @@ -137,7 +137,7 @@ commons: CommonQueryParams = Depends(CommonQueryParams) В этом случае первый `CommonQueryParams`, в: -//// tab | Python 3.8+ +//// tab | Python 3.9+ ```Python commons: Annotated[CommonQueryParams, ... @@ -145,7 +145,7 @@ commons: Annotated[CommonQueryParams, ... //// -//// tab | Python 3.8+ non-Annotated +//// tab | Python 3.9+ non-Annotated /// tip | Подсказка @@ -163,7 +163,7 @@ commons: CommonQueryParams ... На самом деле можно написать просто: -//// tab | Python 3.8+ +//// tab | Python 3.9+ ```Python commons: Annotated[Any, Depends(CommonQueryParams)] @@ -171,7 +171,7 @@ commons: Annotated[Any, Depends(CommonQueryParams)] //// -//// tab | Python 3.8+ non-Annotated +//// tab | Python 3.9+ non-Annotated /// tip | Подсказка @@ -197,7 +197,7 @@ commons = Depends(CommonQueryParams) Но вы видите, что здесь мы имеем некоторое повторение кода, дважды написав `CommonQueryParams`: -//// tab | Python 3.8+ +//// tab | Python 3.9+ ```Python commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)] @@ -205,7 +205,7 @@ commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)] //// -//// tab | Python 3.8+ non-Annotated +//// tab | Python 3.9+ non-Annotated /// tip | Подсказка @@ -225,7 +225,7 @@ commons: CommonQueryParams = Depends(CommonQueryParams) Вместо того чтобы писать: -//// tab | Python 3.8+ +//// tab | Python 3.9+ ```Python commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)] @@ -233,7 +233,7 @@ commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)] //// -//// tab | Python 3.8+ non-Annotated +//// tab | Python 3.9+ non-Annotated /// tip | Подсказка @@ -249,7 +249,7 @@ commons: CommonQueryParams = Depends(CommonQueryParams) ...следует написать: -//// tab | Python 3.8+ +//// tab | Python 3.9+ ```Python commons: Annotated[CommonQueryParams, Depends()] @@ -257,7 +257,7 @@ commons: Annotated[CommonQueryParams, Depends()] //// -//// tab | Python 3.8 non-Annotated +//// tab | Python 3.9+ non-Annotated /// tip | Подсказка diff --git a/docs/ru/docs/tutorial/dependencies/dependencies-with-yield.md b/docs/ru/docs/tutorial/dependencies/dependencies-with-yield.md index 7ff85246dc..dc202db616 100644 --- a/docs/ru/docs/tutorial/dependencies/dependencies-with-yield.md +++ b/docs/ru/docs/tutorial/dependencies/dependencies-with-yield.md @@ -29,15 +29,15 @@ FastAPI поддерживает зависимости, которые выпо Перед созданием ответа будет выполнен только код до и включая оператор `yield`: -{* ../../docs_src/dependencies/tutorial007.py hl[2:4] *} +{* ../../docs_src/dependencies/tutorial007_py39.py hl[2:4] *} Значение, полученное из `yield`, внедряется в *операции пути* и другие зависимости: -{* ../../docs_src/dependencies/tutorial007.py hl[4] *} +{* ../../docs_src/dependencies/tutorial007_py39.py hl[4] *} Код, следующий за оператором `yield`, выполняется после ответа: -{* ../../docs_src/dependencies/tutorial007.py hl[5:6] *} +{* ../../docs_src/dependencies/tutorial007_py39.py hl[5:6] *} /// tip | Подсказка @@ -57,7 +57,7 @@ FastAPI поддерживает зависимости, которые выпо Точно так же можно использовать `finally`, чтобы убедиться, что обязательные шаги при выходе выполнены независимо от того, было ли исключение или нет. -{* ../../docs_src/dependencies/tutorial007.py hl[3,5] *} +{* ../../docs_src/dependencies/tutorial007_py39.py hl[3,5] *} ## Подзависимости с `yield` { #sub-dependencies-with-yield } @@ -269,7 +269,7 @@ with open("./somefile.txt") as f: Их также можно использовать внутри зависимостей **FastAPI** с `yield`, применяя операторы `with` или `async with` внутри функции зависимости: -{* ../../docs_src/dependencies/tutorial010.py hl[1:9,13] *} +{* ../../docs_src/dependencies/tutorial010_py39.py hl[1:9,13] *} /// tip | Подсказка diff --git a/docs/ru/docs/tutorial/dependencies/global-dependencies.md b/docs/ru/docs/tutorial/dependencies/global-dependencies.md index 075d6b0baa..2347c6dd83 100644 --- a/docs/ru/docs/tutorial/dependencies/global-dependencies.md +++ b/docs/ru/docs/tutorial/dependencies/global-dependencies.md @@ -6,7 +6,7 @@ В этом случае они будут применяться ко всем *операциям пути* в приложении: -{* ../../docs_src/dependencies/tutorial012_an_py39.py hl[16] *} +{* ../../docs_src/dependencies/tutorial012_an_py39.py hl[17] *} Все способы [добавления `dependencies` (зависимостей) в *декораторах операций пути*](dependencies-in-path-operation-decorators.md){.internal-link target=_blank} по-прежнему применимы, но в данном случае зависимости применяются ко всем *операциям пути* приложения. diff --git a/docs/ru/docs/tutorial/dependencies/sub-dependencies.md b/docs/ru/docs/tutorial/dependencies/sub-dependencies.md index efe8d98c31..da31a6682f 100644 --- a/docs/ru/docs/tutorial/dependencies/sub-dependencies.md +++ b/docs/ru/docs/tutorial/dependencies/sub-dependencies.md @@ -62,7 +62,7 @@ query_extractor --> query_or_cookie_extractor --> read_query В расширенном сценарии, когда вы знаете, что вам нужно, чтобы зависимость вызывалась на каждом шаге (возможно, несколько раз) в одном и том же запросе, вместо использования "кэшированного" значения, вы можете установить параметр `use_cache=False` при использовании `Depends`: -//// tab | Python 3.8+ +//// tab | Python 3.9+ ```Python hl_lines="1" async def needy_dependency(fresh_value: Annotated[str, Depends(get_value, use_cache=False)]): @@ -71,7 +71,7 @@ async def needy_dependency(fresh_value: Annotated[str, Depends(get_value, use_ca //// -//// tab | Python 3.8+ без Annotated +//// tab | Python 3.9+ без Annotated /// tip | Подсказка diff --git a/docs/ru/docs/tutorial/first-steps.md b/docs/ru/docs/tutorial/first-steps.md index 6f59d72054..798c03d517 100644 --- a/docs/ru/docs/tutorial/first-steps.md +++ b/docs/ru/docs/tutorial/first-steps.md @@ -2,7 +2,7 @@ Самый простой файл FastAPI может выглядеть так: -{* ../../docs_src/first_steps/tutorial001.py *} +{* ../../docs_src/first_steps/tutorial001_py39.py *} Скопируйте это в файл `main.py`. @@ -183,7 +183,7 @@ Deploying to FastAPI Cloud... ### Шаг 1: импортируйте `FastAPI` { #step-1-import-fastapi } -{* ../../docs_src/first_steps/tutorial001.py hl[1] *} +{* ../../docs_src/first_steps/tutorial001_py39.py hl[1] *} `FastAPI` — это класс на Python, который предоставляет всю функциональность для вашего API. @@ -197,7 +197,7 @@ Deploying to FastAPI Cloud... ### Шаг 2: создайте экземпляр `FastAPI` { #step-2-create-a-fastapi-instance } -{* ../../docs_src/first_steps/tutorial001.py hl[3] *} +{* ../../docs_src/first_steps/tutorial001_py39.py hl[3] *} Здесь переменная `app` будет экземпляром класса `FastAPI`. @@ -266,7 +266,7 @@ https://example.com/items/foo #### Определите *декоратор операции пути (path operation decorator)* { #define-a-path-operation-decorator } -{* ../../docs_src/first_steps/tutorial001.py hl[6] *} +{* ../../docs_src/first_steps/tutorial001_py39.py hl[6] *} `@app.get("/")` сообщает **FastAPI**, что функция прямо под ним отвечает за обработку запросов, поступающих: @@ -320,7 +320,7 @@ https://example.com/items/foo * **операция**: `get`. * **функция**: функция ниже «декоратора» (ниже `@app.get("/")`). -{* ../../docs_src/first_steps/tutorial001.py hl[7] *} +{* ../../docs_src/first_steps/tutorial001_py39.py hl[7] *} Это функция на Python. @@ -332,7 +332,7 @@ https://example.com/items/foo Вы также можете определить её как обычную функцию вместо `async def`: -{* ../../docs_src/first_steps/tutorial003.py hl[7] *} +{* ../../docs_src/first_steps/tutorial003_py39.py hl[7] *} /// note | Примечание @@ -342,7 +342,7 @@ https://example.com/items/foo ### Шаг 5: верните содержимое { #step-5-return-the-content } -{* ../../docs_src/first_steps/tutorial001.py hl[8] *} +{* ../../docs_src/first_steps/tutorial001_py39.py hl[8] *} Вы можете вернуть `dict`, `list`, отдельные значения `str`, `int` и т.д. diff --git a/docs/ru/docs/tutorial/handling-errors.md b/docs/ru/docs/tutorial/handling-errors.md index 63ca8665ef..2e00d70759 100644 --- a/docs/ru/docs/tutorial/handling-errors.md +++ b/docs/ru/docs/tutorial/handling-errors.md @@ -25,7 +25,7 @@ ### Импортируйте `HTTPException` { #import-httpexception } -{* ../../docs_src/handling_errors/tutorial001.py hl[1] *} +{* ../../docs_src/handling_errors/tutorial001_py39.py hl[1] *} ### Вызовите `HTTPException` в своем коде { #raise-an-httpexception-in-your-code } @@ -39,7 +39,7 @@ В данном примере, когда клиент запрашивает элемент по несуществующему ID, возникает исключение со статус-кодом `404`: -{* ../../docs_src/handling_errors/tutorial001.py hl[11] *} +{* ../../docs_src/handling_errors/tutorial001_py39.py hl[11] *} ### Возвращаемый ответ { #the-resulting-response } @@ -77,7 +77,7 @@ Но в случае, если это необходимо для продвинутого сценария, можно добавить пользовательские заголовки: -{* ../../docs_src/handling_errors/tutorial002.py hl[14] *} +{* ../../docs_src/handling_errors/tutorial002_py39.py hl[14] *} ## Установка пользовательских обработчиков исключений { #install-custom-exception-handlers } @@ -89,7 +89,7 @@ Можно добавить собственный обработчик исключений с помощью `@app.exception_handler()`: -{* ../../docs_src/handling_errors/tutorial003.py hl[5:7,13:18,24] *} +{* ../../docs_src/handling_errors/tutorial003_py39.py hl[5:7,13:18,24] *} Здесь, если запросить `/unicorns/yolo`, то *операция пути* вызовет `UnicornException`. @@ -127,7 +127,7 @@ Обработчик исключения получит объект `Request` и исключение. -{* ../../docs_src/handling_errors/tutorial004.py hl[2,14:19] *} +{* ../../docs_src/handling_errors/tutorial004_py39.py hl[2,14:19] *} Теперь, если перейти к `/items/foo`, то вместо стандартной JSON-ошибки с: @@ -159,7 +159,7 @@ Field: ('path', 'item_id'), Error: Input should be a valid integer, unable to pa Например, для этих ошибок можно вернуть обычный текстовый ответ вместо JSON: -{* ../../docs_src/handling_errors/tutorial004.py hl[3:4,9:11,25] *} +{* ../../docs_src/handling_errors/tutorial004_py39.py hl[3:4,9:11,25] *} /// note | Технические детали @@ -183,7 +183,7 @@ Field: ('path', 'item_id'), Error: Input should be a valid integer, unable to pa Вы можете использовать его при разработке приложения для регистрации тела и его отладки, возврата пользователю и т.д. -{* ../../docs_src/handling_errors/tutorial005.py hl[14] *} +{* ../../docs_src/handling_errors/tutorial005_py39.py hl[14] *} Теперь попробуйте отправить недействительный элемент, например: @@ -239,6 +239,6 @@ from starlette.exceptions import HTTPException as StarletteHTTPException Если вы хотите использовать исключение вместе с теми же обработчиками исключений по умолчанию из **FastAPI**, вы можете импортировать и повторно использовать обработчики исключений по умолчанию из `fastapi.exception_handlers`: -{* ../../docs_src/handling_errors/tutorial006.py hl[2:5,15,21] *} +{* ../../docs_src/handling_errors/tutorial006_py39.py hl[2:5,15,21] *} В этом примере вы просто `выводите в терминал` ошибку с очень выразительным сообщением, но идея вам понятна. Вы можете использовать исключение, а затем просто повторно использовать стандартные обработчики исключений. diff --git a/docs/ru/docs/tutorial/metadata.md b/docs/ru/docs/tutorial/metadata.md index 2e359752e1..e4fe5fb544 100644 --- a/docs/ru/docs/tutorial/metadata.md +++ b/docs/ru/docs/tutorial/metadata.md @@ -18,7 +18,7 @@ Вы можете задать их следующим образом: -{* ../../docs_src/metadata/tutorial001.py hl[3:16, 19:32] *} +{* ../../docs_src/metadata/tutorial001_py39.py hl[3:16, 19:32] *} /// tip | Подсказка @@ -36,7 +36,7 @@ К примеру: -{* ../../docs_src/metadata/tutorial001_1.py hl[31] *} +{* ../../docs_src/metadata/tutorial001_1_py39.py hl[31] *} ## Метаданные для тегов { #metadata-for-tags } @@ -58,7 +58,7 @@ Создайте метаданные для ваших тегов и передайте их в параметре `openapi_tags`: -{* ../../docs_src/metadata/tutorial004.py hl[3:16,18] *} +{* ../../docs_src/metadata/tutorial004_py39.py hl[3:16,18] *} Помните, что вы можете использовать Markdown внутри описания, к примеру "login" будет отображен жирным шрифтом (**login**) и "fancy" будет отображаться курсивом (_fancy_). @@ -72,7 +72,7 @@ Используйте параметр `tags` с вашими *операциями пути* (и `APIRouter`ами), чтобы присвоить им различные теги: -{* ../../docs_src/metadata/tutorial004.py hl[21,26] *} +{* ../../docs_src/metadata/tutorial004_py39.py hl[21,26] *} /// info | Дополнительная информация @@ -100,7 +100,7 @@ К примеру, чтобы задать её отображение по адресу `/api/v1/openapi.json`: -{* ../../docs_src/metadata/tutorial002.py hl[3] *} +{* ../../docs_src/metadata/tutorial002_py39.py hl[3] *} Если вы хотите отключить схему OpenAPI полностью, вы можете задать `openapi_url=None`, это также отключит пользовательские интерфейсы документации, которые её используют. @@ -117,4 +117,4 @@ К примеру, чтобы задать отображение Swagger UI по адресу `/documentation` и отключить ReDoc: -{* ../../docs_src/metadata/tutorial003.py hl[3] *} +{* ../../docs_src/metadata/tutorial003_py39.py hl[3] *} diff --git a/docs/ru/docs/tutorial/middleware.md b/docs/ru/docs/tutorial/middleware.md index 5803b398b9..a83d3c0111 100644 --- a/docs/ru/docs/tutorial/middleware.md +++ b/docs/ru/docs/tutorial/middleware.md @@ -33,7 +33,7 @@ * Затем она возвращает ответ `response`, сгенерированный *операцией пути*. * Также имеется возможность видоизменить `response`, перед тем как его вернуть. -{* ../../docs_src/middleware/tutorial001.py hl[8:9,11,14] *} +{* ../../docs_src/middleware/tutorial001_py39.py hl[8:9,11,14] *} /// tip | Примечание @@ -59,7 +59,7 @@ Например, вы можете добавить собственный заголовок `X-Process-Time`, содержащий время в секундах, необходимое для обработки запроса и генерации ответа: -{* ../../docs_src/middleware/tutorial001.py hl[10,12:13] *} +{* ../../docs_src/middleware/tutorial001_py39.py hl[10,12:13] *} /// tip | Примечание diff --git a/docs/ru/docs/tutorial/path-operation-configuration.md b/docs/ru/docs/tutorial/path-operation-configuration.md index 63b48a3941..96a54ffea0 100644 --- a/docs/ru/docs/tutorial/path-operation-configuration.md +++ b/docs/ru/docs/tutorial/path-operation-configuration.md @@ -46,7 +46,7 @@ **FastAPI** поддерживает это так же, как и в случае с обычными строками: -{* ../../docs_src/path_operation_configuration/tutorial002b.py hl[1,8:10,13,18] *} +{* ../../docs_src/path_operation_configuration/tutorial002b_py39.py hl[1,8:10,13,18] *} ## Краткое и развёрнутое содержание { #summary-and-description } @@ -92,7 +92,7 @@ OpenAPI указывает, что каждой *операции пути* не Если вам необходимо пометить *операцию пути* как устаревшую, при этом не удаляя её, передайте параметр `deprecated`: -{* ../../docs_src/path_operation_configuration/tutorial006.py hl[16] *} +{* ../../docs_src/path_operation_configuration/tutorial006_py39.py hl[16] *} Он будет четко помечен как устаревший в интерактивной документации: diff --git a/docs/ru/docs/tutorial/path-params-numeric-validations.md b/docs/ru/docs/tutorial/path-params-numeric-validations.md index ccea1945e4..f0fe788051 100644 --- a/docs/ru/docs/tutorial/path-params-numeric-validations.md +++ b/docs/ru/docs/tutorial/path-params-numeric-validations.md @@ -54,7 +54,7 @@ Path-параметр всегда является обязательным, п Поэтому вы можете определить функцию так: -{* ../../docs_src/path_params_numeric_validations/tutorial002.py hl[7] *} +{* ../../docs_src/path_params_numeric_validations/tutorial002_py39.py hl[7] *} Но имейте в виду, что если вы используете `Annotated`, вы не столкнётесь с этой проблемой, так как вы не используете значения по умолчанию параметров функции для `Query()` или `Path()`. @@ -83,7 +83,7 @@ Path-параметр всегда является обязательным, п Python не будет ничего делать с `*`, но он будет знать, что все следующие параметры являются именованными аргументами (парами ключ-значение), также известными как kwargs, даже если у них нет значений по умолчанию. -{* ../../docs_src/path_params_numeric_validations/tutorial003.py hl[7] *} +{* ../../docs_src/path_params_numeric_validations/tutorial003_py39.py hl[7] *} ### Лучше с `Annotated` { #better-with-annotated } diff --git a/docs/ru/docs/tutorial/path-params.md b/docs/ru/docs/tutorial/path-params.md index f7d138afbe..83a7ed3ffe 100644 --- a/docs/ru/docs/tutorial/path-params.md +++ b/docs/ru/docs/tutorial/path-params.md @@ -2,7 +2,7 @@ Вы можете определить "параметры" или "переменные" пути, используя синтаксис форматированных строк Python: -{* ../../docs_src/path_params/tutorial001.py hl[6:7] *} +{* ../../docs_src/path_params/tutorial001_py39.py hl[6:7] *} Значение параметра пути `item_id` будет передано в функцию в качестве аргумента `item_id`. @@ -16,7 +16,7 @@ Вы можете объявить тип параметра пути в функции, используя стандартные аннотации типов Python: -{* ../../docs_src/path_params/tutorial002.py hl[7] *} +{* ../../docs_src/path_params/tutorial002_py39.py hl[7] *} Здесь, `item_id` объявлен типом `int`. @@ -118,13 +118,13 @@ Поскольку *операции пути* выполняются в порядке их объявления, необходимо, чтобы путь для `/users/me` был объявлен раньше, чем путь для `/users/{user_id}`: -{* ../../docs_src/path_params/tutorial003.py hl[6,11] *} +{* ../../docs_src/path_params/tutorial003_py39.py hl[6,11] *} Иначе путь для `/users/{user_id}` также будет соответствовать `/users/me`, "подразумевая", что он получает параметр `user_id` со значением `"me"`. Аналогично, вы не можете переопределить операцию с путем: -{* ../../docs_src/path_params/tutorial003b.py hl[6,11] *} +{* ../../docs_src/path_params/tutorial003b_py39.py hl[6,11] *} Первый будет выполняться всегда, так как путь совпадает первым. @@ -140,13 +140,7 @@ Затем создайте атрибуты класса с фиксированными допустимыми значениями: -{* ../../docs_src/path_params/tutorial005.py hl[1,6:9] *} - -/// info | Дополнительная информация - -Перечисления (enum) доступны в Python начиная с версии 3.4. - -/// +{* ../../docs_src/path_params/tutorial005_py39.py hl[1,6:9] *} /// tip | Подсказка @@ -158,7 +152,7 @@ Определите *параметр пути*, используя в аннотации типа класс перечисления (`ModelName`), созданный ранее: -{* ../../docs_src/path_params/tutorial005.py hl[16] *} +{* ../../docs_src/path_params/tutorial005_py39.py hl[16] *} ### Проверьте документацию { #check-the-docs } @@ -174,13 +168,13 @@ Вы можете сравнить это значение с *элементом перечисления* класса `ModelName`: -{* ../../docs_src/path_params/tutorial005.py hl[17] *} +{* ../../docs_src/path_params/tutorial005_py39.py hl[17] *} #### Получение *значения перечисления* { #get-the-enumeration-value } Можно получить фактическое значение (в данном случае - `str`) с помощью `model_name.value` или в общем случае `your_enum_member.value`: -{* ../../docs_src/path_params/tutorial005.py hl[20] *} +{* ../../docs_src/path_params/tutorial005_py39.py hl[20] *} /// tip | Подсказка @@ -194,7 +188,7 @@ Они будут преобразованы в соответствующие значения (в данном случае - строки) перед их возвратом клиенту: -{* ../../docs_src/path_params/tutorial005.py hl[18,21,23] *} +{* ../../docs_src/path_params/tutorial005_py39.py hl[18,21,23] *} Вы отправите клиенту такой JSON-ответ: ```JSON @@ -232,7 +226,7 @@ OpenAPI не поддерживает способов объявления *п Можете использовать так: -{* ../../docs_src/path_params/tutorial004.py hl[6] *} +{* ../../docs_src/path_params/tutorial004_py39.py hl[6] *} /// tip | Подсказка diff --git a/docs/ru/docs/tutorial/query-params-str-validations.md b/docs/ru/docs/tutorial/query-params-str-validations.md index 302901d4ec..3a4ecc37dc 100644 --- a/docs/ru/docs/tutorial/query-params-str-validations.md +++ b/docs/ru/docs/tutorial/query-params-str-validations.md @@ -55,7 +55,7 @@ q: str | None = None //// -//// tab | Python 3.8+ +//// tab | Python 3.9+ ```Python q: Union[str, None] = None @@ -73,7 +73,7 @@ q: Annotated[str | None] = None //// -//// tab | Python 3.8+ +//// tab | Python 3.9+ ```Python q: Annotated[Union[str, None]] = None diff --git a/docs/ru/docs/tutorial/query-params.md b/docs/ru/docs/tutorial/query-params.md index 5a84f9768c..be1c0e46e1 100644 --- a/docs/ru/docs/tutorial/query-params.md +++ b/docs/ru/docs/tutorial/query-params.md @@ -2,7 +2,7 @@ Когда вы объявляете параметры функции, которые не являются параметрами пути, они автоматически интерпретируются как "query"-параметры. -{* ../../docs_src/query_params/tutorial001.py hl[9] *} +{* ../../docs_src/query_params/tutorial001_py39.py hl[9] *} Query-параметры представляют из себя набор пар ключ-значение, которые идут после знака `?` в URL-адресе, разделенные символами `&`. @@ -127,7 +127,7 @@ http://127.0.0.1:8000/items/foo?short=yes Но если вы хотите сделать query-параметр обязательным, вы можете просто не указывать значение по умолчанию: -{* ../../docs_src/query_params/tutorial005.py hl[6:7] *} +{* ../../docs_src/query_params/tutorial005_py39.py hl[6:7] *} Здесь параметр запроса `needy` является обязательным параметром с типом данных `str`. diff --git a/docs/ru/docs/tutorial/response-model.md b/docs/ru/docs/tutorial/response-model.md index c045f9ed78..07308c1db2 100644 --- a/docs/ru/docs/tutorial/response-model.md +++ b/docs/ru/docs/tutorial/response-model.md @@ -183,7 +183,7 @@ FastAPI делает несколько вещей внутри вместе с Самый распространённый случай — [возвращать Response напрямую, как описано далее в разделах для продвинутых](../advanced/response-directly.md){.internal-link target=_blank}. -{* ../../docs_src/response_model/tutorial003_02.py hl[8,10:11] *} +{* ../../docs_src/response_model/tutorial003_02_py39.py hl[8,10:11] *} Этот простой случай обрабатывается FastAPI автоматически, потому что аннотация возвращаемого типа — это класс (или подкласс) `Response`. @@ -193,7 +193,7 @@ FastAPI делает несколько вещей внутри вместе с Вы также можете использовать подкласс `Response` в аннотации типа: -{* ../../docs_src/response_model/tutorial003_03.py hl[8:9] *} +{* ../../docs_src/response_model/tutorial003_03_py39.py hl[8:9] *} Это тоже сработает, так как `RedirectResponse` — подкласс `Response`, и FastAPI автоматически обработает этот случай. diff --git a/docs/ru/docs/tutorial/response-status-code.md b/docs/ru/docs/tutorial/response-status-code.md index f5b1ff6ad7..30f642b643 100644 --- a/docs/ru/docs/tutorial/response-status-code.md +++ b/docs/ru/docs/tutorial/response-status-code.md @@ -8,7 +8,7 @@ * `@app.delete()` * и других. -{* ../../docs_src/response_status_code/tutorial001.py hl[6] *} +{* ../../docs_src/response_status_code/tutorial001_py39.py hl[6] *} /// note | Примечание @@ -74,7 +74,7 @@ FastAPI знает об этом и создаст документацию Open Рассмотрим предыдущий пример еще раз: -{* ../../docs_src/response_status_code/tutorial001.py hl[6] *} +{* ../../docs_src/response_status_code/tutorial001_py39.py hl[6] *} `201` – это код статуса "Создано". @@ -82,7 +82,7 @@ FastAPI знает об этом и создаст документацию Open Для удобства вы можете использовать переменные из `fastapi.status`. -{* ../../docs_src/response_status_code/tutorial002.py hl[1,6] *} +{* ../../docs_src/response_status_code/tutorial002_py39.py hl[1,6] *} Они содержат те же числовые значения, но позволяют использовать автозавершение редактора кода для выбора кода статуса: diff --git a/docs/ru/docs/tutorial/static-files.md b/docs/ru/docs/tutorial/static-files.md index 8455aea0a2..f40cfe9b04 100644 --- a/docs/ru/docs/tutorial/static-files.md +++ b/docs/ru/docs/tutorial/static-files.md @@ -7,7 +7,7 @@ * Импортируйте `StaticFiles`. * "Примонтируйте" экземпляр `StaticFiles()` к определённому пути. -{* ../../docs_src/static_files/tutorial001.py hl[2,6] *} +{* ../../docs_src/static_files/tutorial001_py39.py hl[2,6] *} /// note | Технические детали diff --git a/docs/ru/docs/tutorial/testing.md b/docs/ru/docs/tutorial/testing.md index 7354ed895f..ab58429c51 100644 --- a/docs/ru/docs/tutorial/testing.md +++ b/docs/ru/docs/tutorial/testing.md @@ -30,7 +30,7 @@ $ pip install httpx Напишите простое утверждение с `assert` дабы проверить истинность Python-выражения (это тоже стандарт `pytest`). -{* ../../docs_src/app_testing/tutorial001.py hl[2,12,15:18] *} +{* ../../docs_src/app_testing/tutorial001_py39.py hl[2,12,15:18] *} /// tip | Подсказка @@ -76,7 +76,7 @@ $ pip install httpx В файле `main.py` находится Ваше приложение **FastAPI**: -{* ../../docs_src/app_testing/main.py *} +{* ../../docs_src/app_testing/app_a_py39/main.py *} ### Файл тестов { #testing-file } @@ -92,7 +92,7 @@ $ pip install httpx Так как оба файла находятся в одной директории, для импорта объекта приложения из файла `main` в файл `test_main` Вы можете использовать относительный импорт: -{* ../../docs_src/app_testing/test_main.py hl[3] *} +{* ../../docs_src/app_testing/app_a_py39/test_main.py hl[3] *} ...и писать дальше тесты, как и раньше. diff --git a/docs_src/additional_responses/tutorial001.py b/docs_src/additional_responses/tutorial001_py39.py similarity index 100% rename from docs_src/additional_responses/tutorial001.py rename to docs_src/additional_responses/tutorial001_py39.py diff --git a/docs_src/additional_responses/tutorial002.py b/docs_src/additional_responses/tutorial002_py39.py similarity index 100% rename from docs_src/additional_responses/tutorial002.py rename to docs_src/additional_responses/tutorial002_py39.py diff --git a/docs_src/additional_responses/tutorial003.py b/docs_src/additional_responses/tutorial003_py39.py similarity index 100% rename from docs_src/additional_responses/tutorial003.py rename to docs_src/additional_responses/tutorial003_py39.py diff --git a/docs_src/additional_responses/tutorial004.py b/docs_src/additional_responses/tutorial004_py39.py similarity index 100% rename from docs_src/additional_responses/tutorial004.py rename to docs_src/additional_responses/tutorial004_py39.py diff --git a/docs_src/additional_status_codes/tutorial001_an.py b/docs_src/additional_status_codes/tutorial001_an.py deleted file mode 100644 index b5ad6a16b6..0000000000 --- a/docs_src/additional_status_codes/tutorial001_an.py +++ /dev/null @@ -1,26 +0,0 @@ -from typing import Union - -from fastapi import Body, FastAPI, status -from fastapi.responses import JSONResponse -from typing_extensions import Annotated - -app = FastAPI() - -items = {"foo": {"name": "Fighters", "size": 6}, "bar": {"name": "Tenders", "size": 3}} - - -@app.put("/items/{item_id}") -async def upsert_item( - item_id: str, - name: Annotated[Union[str, None], Body()] = None, - size: Annotated[Union[int, None], Body()] = None, -): - if item_id in items: - item = items[item_id] - item["name"] = name - item["size"] = size - return item - else: - item = {"name": name, "size": size} - items[item_id] = item - return JSONResponse(status_code=status.HTTP_201_CREATED, content=item) diff --git a/docs_src/additional_status_codes/tutorial001.py b/docs_src/additional_status_codes/tutorial001_py39.py similarity index 100% rename from docs_src/additional_status_codes/tutorial001.py rename to docs_src/additional_status_codes/tutorial001_py39.py diff --git a/docs_src/advanced_middleware/tutorial001.py b/docs_src/advanced_middleware/tutorial001_py39.py similarity index 100% rename from docs_src/advanced_middleware/tutorial001.py rename to docs_src/advanced_middleware/tutorial001_py39.py diff --git a/docs_src/advanced_middleware/tutorial002.py b/docs_src/advanced_middleware/tutorial002_py39.py similarity index 100% rename from docs_src/advanced_middleware/tutorial002.py rename to docs_src/advanced_middleware/tutorial002_py39.py diff --git a/docs_src/advanced_middleware/tutorial003.py b/docs_src/advanced_middleware/tutorial003_py39.py similarity index 100% rename from docs_src/advanced_middleware/tutorial003.py rename to docs_src/advanced_middleware/tutorial003_py39.py diff --git a/docs_src/app_testing/app_b/__init__.py b/docs_src/app_testing/app_a_py39/__init__.py similarity index 100% rename from docs_src/app_testing/app_b/__init__.py rename to docs_src/app_testing/app_a_py39/__init__.py diff --git a/docs_src/app_testing/main.py b/docs_src/app_testing/app_a_py39/main.py similarity index 100% rename from docs_src/app_testing/main.py rename to docs_src/app_testing/app_a_py39/main.py diff --git a/docs_src/app_testing/test_main.py b/docs_src/app_testing/app_a_py39/test_main.py similarity index 100% rename from docs_src/app_testing/test_main.py rename to docs_src/app_testing/app_a_py39/test_main.py diff --git a/docs_src/app_testing/app_b_an/main.py b/docs_src/app_testing/app_b_an/main.py deleted file mode 100644 index c66278fdd0..0000000000 --- a/docs_src/app_testing/app_b_an/main.py +++ /dev/null @@ -1,39 +0,0 @@ -from typing import Union - -from fastapi import FastAPI, Header, HTTPException -from pydantic import BaseModel -from typing_extensions import Annotated - -fake_secret_token = "coneofsilence" - -fake_db = { - "foo": {"id": "foo", "title": "Foo", "description": "There goes my hero"}, - "bar": {"id": "bar", "title": "Bar", "description": "The bartenders"}, -} - -app = FastAPI() - - -class Item(BaseModel): - id: str - title: str - description: Union[str, None] = None - - -@app.get("/items/{item_id}", response_model=Item) -async def read_main(item_id: str, x_token: Annotated[str, Header()]): - if x_token != fake_secret_token: - raise HTTPException(status_code=400, detail="Invalid X-Token header") - if item_id not in fake_db: - raise HTTPException(status_code=404, detail="Item not found") - return fake_db[item_id] - - -@app.post("/items/", response_model=Item) -async def create_item(item: Item, x_token: Annotated[str, Header()]): - if x_token != fake_secret_token: - raise HTTPException(status_code=400, detail="Invalid X-Token header") - if item.id in fake_db: - raise HTTPException(status_code=409, detail="Item already exists") - fake_db[item.id] = item - return item diff --git a/docs_src/app_testing/app_b_an/test_main.py b/docs_src/app_testing/app_b_an/test_main.py deleted file mode 100644 index 4e1c51ecc8..0000000000 --- a/docs_src/app_testing/app_b_an/test_main.py +++ /dev/null @@ -1,65 +0,0 @@ -from fastapi.testclient import TestClient - -from .main import app - -client = TestClient(app) - - -def test_read_item(): - response = client.get("/items/foo", headers={"X-Token": "coneofsilence"}) - assert response.status_code == 200 - assert response.json() == { - "id": "foo", - "title": "Foo", - "description": "There goes my hero", - } - - -def test_read_item_bad_token(): - response = client.get("/items/foo", headers={"X-Token": "hailhydra"}) - assert response.status_code == 400 - assert response.json() == {"detail": "Invalid X-Token header"} - - -def test_read_nonexistent_item(): - response = client.get("/items/baz", headers={"X-Token": "coneofsilence"}) - assert response.status_code == 404 - assert response.json() == {"detail": "Item not found"} - - -def test_create_item(): - response = client.post( - "/items/", - headers={"X-Token": "coneofsilence"}, - json={"id": "foobar", "title": "Foo Bar", "description": "The Foo Barters"}, - ) - assert response.status_code == 200 - assert response.json() == { - "id": "foobar", - "title": "Foo Bar", - "description": "The Foo Barters", - } - - -def test_create_item_bad_token(): - response = client.post( - "/items/", - headers={"X-Token": "hailhydra"}, - json={"id": "bazz", "title": "Bazz", "description": "Drop the bazz"}, - ) - assert response.status_code == 400 - assert response.json() == {"detail": "Invalid X-Token header"} - - -def test_create_existing_item(): - response = client.post( - "/items/", - headers={"X-Token": "coneofsilence"}, - json={ - "id": "foo", - "title": "The Foo ID Stealers", - "description": "There goes my stealer", - }, - ) - assert response.status_code == 409 - assert response.json() == {"detail": "Item already exists"} diff --git a/docs_src/app_testing/app_b_an/__init__.py b/docs_src/app_testing/app_b_py39/__init__.py similarity index 100% rename from docs_src/app_testing/app_b_an/__init__.py rename to docs_src/app_testing/app_b_py39/__init__.py diff --git a/docs_src/app_testing/app_b/main.py b/docs_src/app_testing/app_b_py39/main.py similarity index 100% rename from docs_src/app_testing/app_b/main.py rename to docs_src/app_testing/app_b_py39/main.py diff --git a/docs_src/app_testing/app_b/test_main.py b/docs_src/app_testing/app_b_py39/test_main.py similarity index 100% rename from docs_src/app_testing/app_b/test_main.py rename to docs_src/app_testing/app_b_py39/test_main.py diff --git a/docs_src/app_testing/tutorial001.py b/docs_src/app_testing/tutorial001_py39.py similarity index 100% rename from docs_src/app_testing/tutorial001.py rename to docs_src/app_testing/tutorial001_py39.py diff --git a/docs_src/app_testing/tutorial002.py b/docs_src/app_testing/tutorial002_py39.py similarity index 100% rename from docs_src/app_testing/tutorial002.py rename to docs_src/app_testing/tutorial002_py39.py diff --git a/docs_src/app_testing/tutorial003.py b/docs_src/app_testing/tutorial003_py39.py similarity index 100% rename from docs_src/app_testing/tutorial003.py rename to docs_src/app_testing/tutorial003_py39.py diff --git a/docs_src/app_testing/tutorial004.py b/docs_src/app_testing/tutorial004_py39.py similarity index 100% rename from docs_src/app_testing/tutorial004.py rename to docs_src/app_testing/tutorial004_py39.py diff --git a/docs_src/bigger_applications/app/__init__.py b/docs_src/async_tests/app_a_py39/__init__.py similarity index 100% rename from docs_src/bigger_applications/app/__init__.py rename to docs_src/async_tests/app_a_py39/__init__.py diff --git a/docs_src/async_tests/main.py b/docs_src/async_tests/app_a_py39/main.py similarity index 100% rename from docs_src/async_tests/main.py rename to docs_src/async_tests/app_a_py39/main.py diff --git a/docs_src/async_tests/test_main.py b/docs_src/async_tests/app_a_py39/test_main.py similarity index 100% rename from docs_src/async_tests/test_main.py rename to docs_src/async_tests/app_a_py39/test_main.py diff --git a/docs_src/authentication_error_status_code/tutorial001_an.py b/docs_src/authentication_error_status_code/tutorial001_an.py deleted file mode 100644 index 40678e858d..0000000000 --- a/docs_src/authentication_error_status_code/tutorial001_an.py +++ /dev/null @@ -1,20 +0,0 @@ -from fastapi import Depends, FastAPI, HTTPException, status -from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer -from typing_extensions import Annotated - -app = FastAPI() - - -class HTTPBearer403(HTTPBearer): - def make_not_authenticated_error(self) -> HTTPException: - return HTTPException( - status_code=status.HTTP_403_FORBIDDEN, detail="Not authenticated" - ) - - -CredentialsDep = Annotated[HTTPAuthorizationCredentials, Depends(HTTPBearer403())] - - -@app.get("/me") -def read_me(credentials: CredentialsDep): - return {"message": "You are authenticated", "token": credentials.credentials} diff --git a/docs_src/background_tasks/tutorial001.py b/docs_src/background_tasks/tutorial001_py39.py similarity index 100% rename from docs_src/background_tasks/tutorial001.py rename to docs_src/background_tasks/tutorial001_py39.py diff --git a/docs_src/background_tasks/tutorial002_an.py b/docs_src/background_tasks/tutorial002_an.py deleted file mode 100644 index f63502b09a..0000000000 --- a/docs_src/background_tasks/tutorial002_an.py +++ /dev/null @@ -1,27 +0,0 @@ -from typing import Union - -from fastapi import BackgroundTasks, Depends, FastAPI -from typing_extensions import Annotated - -app = FastAPI() - - -def write_log(message: str): - with open("log.txt", mode="a") as log: - log.write(message) - - -def get_query(background_tasks: BackgroundTasks, q: Union[str, None] = None): - if q: - message = f"found query: {q}\n" - background_tasks.add_task(write_log, message) - return q - - -@app.post("/send-notification/{email}") -async def send_notification( - email: str, background_tasks: BackgroundTasks, q: Annotated[str, Depends(get_query)] -): - message = f"message to {email}\n" - background_tasks.add_task(write_log, message) - return {"message": "Message sent"} diff --git a/docs_src/background_tasks/tutorial002.py b/docs_src/background_tasks/tutorial002_py39.py similarity index 100% rename from docs_src/background_tasks/tutorial002.py rename to docs_src/background_tasks/tutorial002_py39.py diff --git a/docs_src/behind_a_proxy/tutorial001_01.py b/docs_src/behind_a_proxy/tutorial001_01_py39.py similarity index 100% rename from docs_src/behind_a_proxy/tutorial001_01.py rename to docs_src/behind_a_proxy/tutorial001_01_py39.py diff --git a/docs_src/behind_a_proxy/tutorial001.py b/docs_src/behind_a_proxy/tutorial001_py39.py similarity index 100% rename from docs_src/behind_a_proxy/tutorial001.py rename to docs_src/behind_a_proxy/tutorial001_py39.py diff --git a/docs_src/behind_a_proxy/tutorial002.py b/docs_src/behind_a_proxy/tutorial002_py39.py similarity index 100% rename from docs_src/behind_a_proxy/tutorial002.py rename to docs_src/behind_a_proxy/tutorial002_py39.py diff --git a/docs_src/behind_a_proxy/tutorial003.py b/docs_src/behind_a_proxy/tutorial003_py39.py similarity index 100% rename from docs_src/behind_a_proxy/tutorial003.py rename to docs_src/behind_a_proxy/tutorial003_py39.py diff --git a/docs_src/behind_a_proxy/tutorial004.py b/docs_src/behind_a_proxy/tutorial004_py39.py similarity index 100% rename from docs_src/behind_a_proxy/tutorial004.py rename to docs_src/behind_a_proxy/tutorial004_py39.py diff --git a/docs_src/bigger_applications/app_an/dependencies.py b/docs_src/bigger_applications/app_an/dependencies.py deleted file mode 100644 index 1374c54b31..0000000000 --- a/docs_src/bigger_applications/app_an/dependencies.py +++ /dev/null @@ -1,12 +0,0 @@ -from fastapi import Header, HTTPException -from typing_extensions import Annotated - - -async def get_token_header(x_token: Annotated[str, Header()]): - if x_token != "fake-super-secret-token": - raise HTTPException(status_code=400, detail="X-Token header invalid") - - -async def get_query_token(token: str): - if token != "jessica": - raise HTTPException(status_code=400, detail="No Jessica token provided") diff --git a/docs_src/bigger_applications/app_an/internal/admin.py b/docs_src/bigger_applications/app_an/internal/admin.py deleted file mode 100644 index 99d3da86b9..0000000000 --- a/docs_src/bigger_applications/app_an/internal/admin.py +++ /dev/null @@ -1,8 +0,0 @@ -from fastapi import APIRouter - -router = APIRouter() - - -@router.post("/") -async def update_admin(): - return {"message": "Admin getting schwifty"} diff --git a/docs_src/bigger_applications/app_an/main.py b/docs_src/bigger_applications/app_an/main.py deleted file mode 100644 index ae544a3aac..0000000000 --- a/docs_src/bigger_applications/app_an/main.py +++ /dev/null @@ -1,23 +0,0 @@ -from fastapi import Depends, FastAPI - -from .dependencies import get_query_token, get_token_header -from .internal import admin -from .routers import items, users - -app = FastAPI(dependencies=[Depends(get_query_token)]) - - -app.include_router(users.router) -app.include_router(items.router) -app.include_router( - admin.router, - prefix="/admin", - tags=["admin"], - dependencies=[Depends(get_token_header)], - responses={418: {"description": "I'm a teapot"}}, -) - - -@app.get("/") -async def root(): - return {"message": "Hello Bigger Applications!"} diff --git a/docs_src/bigger_applications/app_an/routers/items.py b/docs_src/bigger_applications/app_an/routers/items.py deleted file mode 100644 index bde9ff4d55..0000000000 --- a/docs_src/bigger_applications/app_an/routers/items.py +++ /dev/null @@ -1,38 +0,0 @@ -from fastapi import APIRouter, Depends, HTTPException - -from ..dependencies import get_token_header - -router = APIRouter( - prefix="/items", - tags=["items"], - dependencies=[Depends(get_token_header)], - responses={404: {"description": "Not found"}}, -) - - -fake_items_db = {"plumbus": {"name": "Plumbus"}, "gun": {"name": "Portal Gun"}} - - -@router.get("/") -async def read_items(): - return fake_items_db - - -@router.get("/{item_id}") -async def read_item(item_id: str): - if item_id not in fake_items_db: - raise HTTPException(status_code=404, detail="Item not found") - return {"name": fake_items_db[item_id]["name"], "item_id": item_id} - - -@router.put( - "/{item_id}", - tags=["custom"], - responses={403: {"description": "Operation forbidden"}}, -) -async def update_item(item_id: str): - if item_id != "plumbus": - raise HTTPException( - status_code=403, detail="You can only update the item: plumbus" - ) - return {"item_id": item_id, "name": "The great Plumbus"} diff --git a/docs_src/bigger_applications/app_an/routers/users.py b/docs_src/bigger_applications/app_an/routers/users.py deleted file mode 100644 index 39b3d7e7cf..0000000000 --- a/docs_src/bigger_applications/app_an/routers/users.py +++ /dev/null @@ -1,18 +0,0 @@ -from fastapi import APIRouter - -router = APIRouter() - - -@router.get("/users/", tags=["users"]) -async def read_users(): - return [{"username": "Rick"}, {"username": "Morty"}] - - -@router.get("/users/me", tags=["users"]) -async def read_user_me(): - return {"username": "fakecurrentuser"} - - -@router.get("/users/{username}", tags=["users"]) -async def read_user(username: str): - return {"username": username} diff --git a/docs_src/bigger_applications/app/internal/__init__.py b/docs_src/bigger_applications/app_py39/__init__.py similarity index 100% rename from docs_src/bigger_applications/app/internal/__init__.py rename to docs_src/bigger_applications/app_py39/__init__.py diff --git a/docs_src/bigger_applications/app/dependencies.py b/docs_src/bigger_applications/app_py39/dependencies.py similarity index 100% rename from docs_src/bigger_applications/app/dependencies.py rename to docs_src/bigger_applications/app_py39/dependencies.py diff --git a/docs_src/bigger_applications/app/routers/__init__.py b/docs_src/bigger_applications/app_py39/internal/__init__.py similarity index 100% rename from docs_src/bigger_applications/app/routers/__init__.py rename to docs_src/bigger_applications/app_py39/internal/__init__.py diff --git a/docs_src/bigger_applications/app/internal/admin.py b/docs_src/bigger_applications/app_py39/internal/admin.py similarity index 100% rename from docs_src/bigger_applications/app/internal/admin.py rename to docs_src/bigger_applications/app_py39/internal/admin.py diff --git a/docs_src/bigger_applications/app/main.py b/docs_src/bigger_applications/app_py39/main.py similarity index 100% rename from docs_src/bigger_applications/app/main.py rename to docs_src/bigger_applications/app_py39/main.py diff --git a/docs_src/bigger_applications/app_an/__init__.py b/docs_src/bigger_applications/app_py39/routers/__init__.py similarity index 100% rename from docs_src/bigger_applications/app_an/__init__.py rename to docs_src/bigger_applications/app_py39/routers/__init__.py diff --git a/docs_src/bigger_applications/app/routers/items.py b/docs_src/bigger_applications/app_py39/routers/items.py similarity index 100% rename from docs_src/bigger_applications/app/routers/items.py rename to docs_src/bigger_applications/app_py39/routers/items.py diff --git a/docs_src/bigger_applications/app/routers/users.py b/docs_src/bigger_applications/app_py39/routers/users.py similarity index 100% rename from docs_src/bigger_applications/app/routers/users.py rename to docs_src/bigger_applications/app_py39/routers/users.py diff --git a/docs_src/body/tutorial001.py b/docs_src/body/tutorial001_py39.py similarity index 100% rename from docs_src/body/tutorial001.py rename to docs_src/body/tutorial001_py39.py diff --git a/docs_src/body/tutorial002.py b/docs_src/body/tutorial002_py39.py similarity index 100% rename from docs_src/body/tutorial002.py rename to docs_src/body/tutorial002_py39.py diff --git a/docs_src/body/tutorial003.py b/docs_src/body/tutorial003_py39.py similarity index 100% rename from docs_src/body/tutorial003.py rename to docs_src/body/tutorial003_py39.py diff --git a/docs_src/body/tutorial004.py b/docs_src/body/tutorial004_py39.py similarity index 100% rename from docs_src/body/tutorial004.py rename to docs_src/body/tutorial004_py39.py diff --git a/docs_src/body_fields/tutorial001_an.py b/docs_src/body_fields/tutorial001_an.py deleted file mode 100644 index 15ea1b53dc..0000000000 --- a/docs_src/body_fields/tutorial001_an.py +++ /dev/null @@ -1,22 +0,0 @@ -from typing import Union - -from fastapi import Body, FastAPI -from pydantic import BaseModel, Field -from typing_extensions import Annotated - -app = FastAPI() - - -class Item(BaseModel): - name: str - description: Union[str, None] = Field( - default=None, title="The description of the item", max_length=300 - ) - price: float = Field(gt=0, description="The price must be greater than zero") - tax: Union[float, None] = None - - -@app.put("/items/{item_id}") -async def update_item(item_id: int, item: Annotated[Item, Body(embed=True)]): - results = {"item_id": item_id, "item": item} - return results diff --git a/docs_src/body_fields/tutorial001.py b/docs_src/body_fields/tutorial001_py39.py similarity index 100% rename from docs_src/body_fields/tutorial001.py rename to docs_src/body_fields/tutorial001_py39.py diff --git a/docs_src/body_multiple_params/tutorial001_an.py b/docs_src/body_multiple_params/tutorial001_an.py deleted file mode 100644 index 308eee8544..0000000000 --- a/docs_src/body_multiple_params/tutorial001_an.py +++ /dev/null @@ -1,28 +0,0 @@ -from typing import Union - -from fastapi import FastAPI, Path -from pydantic import BaseModel -from typing_extensions import Annotated - -app = FastAPI() - - -class Item(BaseModel): - name: str - description: Union[str, None] = None - price: float - tax: Union[float, None] = None - - -@app.put("/items/{item_id}") -async def update_item( - item_id: Annotated[int, Path(title="The ID of the item to get", ge=0, le=1000)], - q: Union[str, None] = None, - item: Union[Item, None] = None, -): - results = {"item_id": item_id} - if q: - results.update({"q": q}) - if item: - results.update({"item": item}) - return results diff --git a/docs_src/body_multiple_params/tutorial001.py b/docs_src/body_multiple_params/tutorial001_py39.py similarity index 100% rename from docs_src/body_multiple_params/tutorial001.py rename to docs_src/body_multiple_params/tutorial001_py39.py diff --git a/docs_src/body_multiple_params/tutorial002.py b/docs_src/body_multiple_params/tutorial002_py39.py similarity index 100% rename from docs_src/body_multiple_params/tutorial002.py rename to docs_src/body_multiple_params/tutorial002_py39.py diff --git a/docs_src/body_multiple_params/tutorial003_an.py b/docs_src/body_multiple_params/tutorial003_an.py deleted file mode 100644 index 39ef7340a5..0000000000 --- a/docs_src/body_multiple_params/tutorial003_an.py +++ /dev/null @@ -1,27 +0,0 @@ -from typing import Union - -from fastapi import Body, FastAPI -from pydantic import BaseModel -from typing_extensions import Annotated - -app = FastAPI() - - -class Item(BaseModel): - name: str - description: Union[str, None] = None - price: float - tax: Union[float, None] = None - - -class User(BaseModel): - username: str - full_name: Union[str, None] = None - - -@app.put("/items/{item_id}") -async def update_item( - item_id: int, item: Item, user: User, importance: Annotated[int, Body()] -): - results = {"item_id": item_id, "item": item, "user": user, "importance": importance} - return results diff --git a/docs_src/body_multiple_params/tutorial003.py b/docs_src/body_multiple_params/tutorial003_py39.py similarity index 100% rename from docs_src/body_multiple_params/tutorial003.py rename to docs_src/body_multiple_params/tutorial003_py39.py diff --git a/docs_src/body_multiple_params/tutorial004_an.py b/docs_src/body_multiple_params/tutorial004_an.py deleted file mode 100644 index f6830f3920..0000000000 --- a/docs_src/body_multiple_params/tutorial004_an.py +++ /dev/null @@ -1,34 +0,0 @@ -from typing import Union - -from fastapi import Body, FastAPI -from pydantic import BaseModel -from typing_extensions import Annotated - -app = FastAPI() - - -class Item(BaseModel): - name: str - description: Union[str, None] = None - price: float - tax: Union[float, None] = None - - -class User(BaseModel): - username: str - full_name: Union[str, None] = None - - -@app.put("/items/{item_id}") -async def update_item( - *, - item_id: int, - item: Item, - user: User, - importance: Annotated[int, Body(gt=0)], - q: Union[str, None] = None, -): - results = {"item_id": item_id, "item": item, "user": user, "importance": importance} - if q: - results.update({"q": q}) - return results diff --git a/docs_src/body_multiple_params/tutorial004.py b/docs_src/body_multiple_params/tutorial004_py39.py similarity index 100% rename from docs_src/body_multiple_params/tutorial004.py rename to docs_src/body_multiple_params/tutorial004_py39.py diff --git a/docs_src/body_multiple_params/tutorial005_an.py b/docs_src/body_multiple_params/tutorial005_an.py deleted file mode 100644 index dadde80b55..0000000000 --- a/docs_src/body_multiple_params/tutorial005_an.py +++ /dev/null @@ -1,20 +0,0 @@ -from typing import Union - -from fastapi import Body, FastAPI -from pydantic import BaseModel -from typing_extensions import Annotated - -app = FastAPI() - - -class Item(BaseModel): - name: str - description: Union[str, None] = None - price: float - tax: Union[float, None] = None - - -@app.put("/items/{item_id}") -async def update_item(item_id: int, item: Annotated[Item, Body(embed=True)]): - results = {"item_id": item_id, "item": item} - return results diff --git a/docs_src/body_multiple_params/tutorial005.py b/docs_src/body_multiple_params/tutorial005_py39.py similarity index 100% rename from docs_src/body_multiple_params/tutorial005.py rename to docs_src/body_multiple_params/tutorial005_py39.py diff --git a/docs_src/body_nested_models/tutorial001.py b/docs_src/body_nested_models/tutorial001_py39.py similarity index 100% rename from docs_src/body_nested_models/tutorial001.py rename to docs_src/body_nested_models/tutorial001_py39.py diff --git a/docs_src/body_nested_models/tutorial002.py b/docs_src/body_nested_models/tutorial002.py deleted file mode 100644 index 155cff7885..0000000000 --- a/docs_src/body_nested_models/tutorial002.py +++ /dev/null @@ -1,20 +0,0 @@ -from typing import List, Union - -from fastapi import FastAPI -from pydantic import BaseModel - -app = FastAPI() - - -class Item(BaseModel): - name: str - description: Union[str, None] = None - price: float - tax: Union[float, None] = None - tags: List[str] = [] - - -@app.put("/items/{item_id}") -async def update_item(item_id: int, item: Item): - results = {"item_id": item_id, "item": item} - return results diff --git a/docs_src/body_nested_models/tutorial003.py b/docs_src/body_nested_models/tutorial003.py deleted file mode 100644 index 84ed18bf48..0000000000 --- a/docs_src/body_nested_models/tutorial003.py +++ /dev/null @@ -1,20 +0,0 @@ -from typing import Set, Union - -from fastapi import FastAPI -from pydantic import BaseModel - -app = FastAPI() - - -class Item(BaseModel): - name: str - description: Union[str, None] = None - price: float - tax: Union[float, None] = None - tags: Set[str] = set() - - -@app.put("/items/{item_id}") -async def update_item(item_id: int, item: Item): - results = {"item_id": item_id, "item": item} - return results diff --git a/docs_src/body_nested_models/tutorial004.py b/docs_src/body_nested_models/tutorial004.py deleted file mode 100644 index a07bfacac1..0000000000 --- a/docs_src/body_nested_models/tutorial004.py +++ /dev/null @@ -1,26 +0,0 @@ -from typing import Set, Union - -from fastapi import FastAPI -from pydantic import BaseModel - -app = FastAPI() - - -class Image(BaseModel): - url: str - name: str - - -class Item(BaseModel): - name: str - description: Union[str, None] = None - price: float - tax: Union[float, None] = None - tags: Set[str] = set() - image: Union[Image, None] = None - - -@app.put("/items/{item_id}") -async def update_item(item_id: int, item: Item): - results = {"item_id": item_id, "item": item} - return results diff --git a/docs_src/body_nested_models/tutorial005.py b/docs_src/body_nested_models/tutorial005.py deleted file mode 100644 index 5a01264eda..0000000000 --- a/docs_src/body_nested_models/tutorial005.py +++ /dev/null @@ -1,26 +0,0 @@ -from typing import Set, Union - -from fastapi import FastAPI -from pydantic import BaseModel, HttpUrl - -app = FastAPI() - - -class Image(BaseModel): - url: HttpUrl - name: str - - -class Item(BaseModel): - name: str - description: Union[str, None] = None - price: float - tax: Union[float, None] = None - tags: Set[str] = set() - image: Union[Image, None] = None - - -@app.put("/items/{item_id}") -async def update_item(item_id: int, item: Item): - results = {"item_id": item_id, "item": item} - return results diff --git a/docs_src/body_nested_models/tutorial006.py b/docs_src/body_nested_models/tutorial006.py deleted file mode 100644 index 75f1f30e33..0000000000 --- a/docs_src/body_nested_models/tutorial006.py +++ /dev/null @@ -1,26 +0,0 @@ -from typing import List, Set, Union - -from fastapi import FastAPI -from pydantic import BaseModel, HttpUrl - -app = FastAPI() - - -class Image(BaseModel): - url: HttpUrl - name: str - - -class Item(BaseModel): - name: str - description: Union[str, None] = None - price: float - tax: Union[float, None] = None - tags: Set[str] = set() - images: Union[List[Image], None] = None - - -@app.put("/items/{item_id}") -async def update_item(item_id: int, item: Item): - results = {"item_id": item_id, "item": item} - return results diff --git a/docs_src/body_nested_models/tutorial007.py b/docs_src/body_nested_models/tutorial007.py deleted file mode 100644 index 641f09dced..0000000000 --- a/docs_src/body_nested_models/tutorial007.py +++ /dev/null @@ -1,32 +0,0 @@ -from typing import List, Set, Union - -from fastapi import FastAPI -from pydantic import BaseModel, HttpUrl - -app = FastAPI() - - -class Image(BaseModel): - url: HttpUrl - name: str - - -class Item(BaseModel): - name: str - description: Union[str, None] = None - price: float - tax: Union[float, None] = None - tags: Set[str] = set() - images: Union[List[Image], None] = None - - -class Offer(BaseModel): - name: str - description: Union[str, None] = None - price: float - items: List[Item] - - -@app.post("/offers/") -async def create_offer(offer: Offer): - return offer diff --git a/docs_src/body_nested_models/tutorial008.py b/docs_src/body_nested_models/tutorial008.py deleted file mode 100644 index 3431cc6365..0000000000 --- a/docs_src/body_nested_models/tutorial008.py +++ /dev/null @@ -1,16 +0,0 @@ -from typing import List - -from fastapi import FastAPI -from pydantic import BaseModel, HttpUrl - -app = FastAPI() - - -class Image(BaseModel): - url: HttpUrl - name: str - - -@app.post("/images/multiple/") -async def create_multiple_images(images: List[Image]): - return images diff --git a/docs_src/body_nested_models/tutorial009.py b/docs_src/body_nested_models/tutorial009.py deleted file mode 100644 index 41dce946ec..0000000000 --- a/docs_src/body_nested_models/tutorial009.py +++ /dev/null @@ -1,10 +0,0 @@ -from typing import Dict - -from fastapi import FastAPI - -app = FastAPI() - - -@app.post("/index-weights/") -async def create_index_weights(weights: Dict[int, float]): - return weights diff --git a/docs_src/body_updates/tutorial001.py b/docs_src/body_updates/tutorial001.py deleted file mode 100644 index 4e65d77e26..0000000000 --- a/docs_src/body_updates/tutorial001.py +++ /dev/null @@ -1,34 +0,0 @@ -from typing import List, Union - -from fastapi import FastAPI -from fastapi.encoders import jsonable_encoder -from pydantic import BaseModel - -app = FastAPI() - - -class Item(BaseModel): - name: Union[str, None] = None - description: Union[str, None] = None - price: Union[float, None] = None - tax: float = 10.5 - tags: List[str] = [] - - -items = { - "foo": {"name": "Foo", "price": 50.2}, - "bar": {"name": "Bar", "description": "The bartenders", "price": 62, "tax": 20.2}, - "baz": {"name": "Baz", "description": None, "price": 50.2, "tax": 10.5, "tags": []}, -} - - -@app.get("/items/{item_id}", response_model=Item) -async def read_item(item_id: str): - return items[item_id] - - -@app.put("/items/{item_id}", response_model=Item) -async def update_item(item_id: str, item: Item): - update_item_encoded = jsonable_encoder(item) - items[item_id] = update_item_encoded - return update_item_encoded diff --git a/docs_src/body_updates/tutorial002.py b/docs_src/body_updates/tutorial002.py deleted file mode 100644 index c3a0fe79ea..0000000000 --- a/docs_src/body_updates/tutorial002.py +++ /dev/null @@ -1,37 +0,0 @@ -from typing import List, Union - -from fastapi import FastAPI -from fastapi.encoders import jsonable_encoder -from pydantic import BaseModel - -app = FastAPI() - - -class Item(BaseModel): - name: Union[str, None] = None - description: Union[str, None] = None - price: Union[float, None] = None - tax: float = 10.5 - tags: List[str] = [] - - -items = { - "foo": {"name": "Foo", "price": 50.2}, - "bar": {"name": "Bar", "description": "The bartenders", "price": 62, "tax": 20.2}, - "baz": {"name": "Baz", "description": None, "price": 50.2, "tax": 10.5, "tags": []}, -} - - -@app.get("/items/{item_id}", response_model=Item) -async def read_item(item_id: str): - return items[item_id] - - -@app.patch("/items/{item_id}", response_model=Item) -async def update_item(item_id: str, item: Item): - stored_item_data = items[item_id] - stored_item_model = Item(**stored_item_data) - update_data = item.dict(exclude_unset=True) - updated_item = stored_item_model.copy(update=update_data) - items[item_id] = jsonable_encoder(updated_item) - return updated_item diff --git a/docs_src/conditional_openapi/tutorial001.py b/docs_src/conditional_openapi/tutorial001_py39.py similarity index 100% rename from docs_src/conditional_openapi/tutorial001.py rename to docs_src/conditional_openapi/tutorial001_py39.py diff --git a/docs_src/configure_swagger_ui/tutorial001.py b/docs_src/configure_swagger_ui/tutorial001_py39.py similarity index 100% rename from docs_src/configure_swagger_ui/tutorial001.py rename to docs_src/configure_swagger_ui/tutorial001_py39.py diff --git a/docs_src/configure_swagger_ui/tutorial002.py b/docs_src/configure_swagger_ui/tutorial002_py39.py similarity index 100% rename from docs_src/configure_swagger_ui/tutorial002.py rename to docs_src/configure_swagger_ui/tutorial002_py39.py diff --git a/docs_src/configure_swagger_ui/tutorial003.py b/docs_src/configure_swagger_ui/tutorial003_py39.py similarity index 100% rename from docs_src/configure_swagger_ui/tutorial003.py rename to docs_src/configure_swagger_ui/tutorial003_py39.py diff --git a/docs_src/cookie_param_models/tutorial001_an.py b/docs_src/cookie_param_models/tutorial001_an.py deleted file mode 100644 index e5839ffd54..0000000000 --- a/docs_src/cookie_param_models/tutorial001_an.py +++ /dev/null @@ -1,18 +0,0 @@ -from typing import Union - -from fastapi import Cookie, FastAPI -from pydantic import BaseModel -from typing_extensions import Annotated - -app = FastAPI() - - -class Cookies(BaseModel): - session_id: str - fatebook_tracker: Union[str, None] = None - googall_tracker: Union[str, None] = None - - -@app.get("/items/") -async def read_items(cookies: Annotated[Cookies, Cookie()]): - return cookies diff --git a/docs_src/cookie_param_models/tutorial001.py b/docs_src/cookie_param_models/tutorial001_py39.py similarity index 100% rename from docs_src/cookie_param_models/tutorial001.py rename to docs_src/cookie_param_models/tutorial001_py39.py diff --git a/docs_src/cookie_param_models/tutorial002_an.py b/docs_src/cookie_param_models/tutorial002_an.py deleted file mode 100644 index ce5644b7bd..0000000000 --- a/docs_src/cookie_param_models/tutorial002_an.py +++ /dev/null @@ -1,20 +0,0 @@ -from typing import Union - -from fastapi import Cookie, FastAPI -from pydantic import BaseModel -from typing_extensions import Annotated - -app = FastAPI() - - -class Cookies(BaseModel): - model_config = {"extra": "forbid"} - - session_id: str - fatebook_tracker: Union[str, None] = None - googall_tracker: Union[str, None] = None - - -@app.get("/items/") -async def read_items(cookies: Annotated[Cookies, Cookie()]): - return cookies diff --git a/docs_src/cookie_param_models/tutorial002_pv1_an.py b/docs_src/cookie_param_models/tutorial002_pv1_an.py deleted file mode 100644 index ddfda9b6f5..0000000000 --- a/docs_src/cookie_param_models/tutorial002_pv1_an.py +++ /dev/null @@ -1,21 +0,0 @@ -from typing import Union - -from fastapi import Cookie, FastAPI -from pydantic import BaseModel -from typing_extensions import Annotated - -app = FastAPI() - - -class Cookies(BaseModel): - class Config: - extra = "forbid" - - session_id: str - fatebook_tracker: Union[str, None] = None - googall_tracker: Union[str, None] = None - - -@app.get("/items/") -async def read_items(cookies: Annotated[Cookies, Cookie()]): - return cookies diff --git a/docs_src/cookie_param_models/tutorial002_pv1.py b/docs_src/cookie_param_models/tutorial002_pv1_py39.py similarity index 100% rename from docs_src/cookie_param_models/tutorial002_pv1.py rename to docs_src/cookie_param_models/tutorial002_pv1_py39.py diff --git a/docs_src/cookie_param_models/tutorial002.py b/docs_src/cookie_param_models/tutorial002_py39.py similarity index 100% rename from docs_src/cookie_param_models/tutorial002.py rename to docs_src/cookie_param_models/tutorial002_py39.py diff --git a/docs_src/cookie_params/tutorial001_an.py b/docs_src/cookie_params/tutorial001_an.py deleted file mode 100644 index 6d5931229c..0000000000 --- a/docs_src/cookie_params/tutorial001_an.py +++ /dev/null @@ -1,11 +0,0 @@ -from typing import Union - -from fastapi import Cookie, FastAPI -from typing_extensions import Annotated - -app = FastAPI() - - -@app.get("/items/") -async def read_items(ads_id: Annotated[Union[str, None], Cookie()] = None): - return {"ads_id": ads_id} diff --git a/docs_src/cookie_params/tutorial001.py b/docs_src/cookie_params/tutorial001_py39.py similarity index 100% rename from docs_src/cookie_params/tutorial001.py rename to docs_src/cookie_params/tutorial001_py39.py diff --git a/docs_src/cors/tutorial001.py b/docs_src/cors/tutorial001_py39.py similarity index 100% rename from docs_src/cors/tutorial001.py rename to docs_src/cors/tutorial001_py39.py diff --git a/docs_src/custom_docs_ui/tutorial001.py b/docs_src/custom_docs_ui/tutorial001_py39.py similarity index 100% rename from docs_src/custom_docs_ui/tutorial001.py rename to docs_src/custom_docs_ui/tutorial001_py39.py diff --git a/docs_src/custom_docs_ui/tutorial002.py b/docs_src/custom_docs_ui/tutorial002_py39.py similarity index 100% rename from docs_src/custom_docs_ui/tutorial002.py rename to docs_src/custom_docs_ui/tutorial002_py39.py diff --git a/docs_src/custom_request_and_route/tutorial001.py b/docs_src/custom_request_and_route/tutorial001.py deleted file mode 100644 index 268ce9019e..0000000000 --- a/docs_src/custom_request_and_route/tutorial001.py +++ /dev/null @@ -1,35 +0,0 @@ -import gzip -from typing import Callable, List - -from fastapi import Body, FastAPI, Request, Response -from fastapi.routing import APIRoute - - -class GzipRequest(Request): - async def body(self) -> bytes: - if not hasattr(self, "_body"): - body = await super().body() - if "gzip" in self.headers.getlist("Content-Encoding"): - body = gzip.decompress(body) - self._body = body - return self._body - - -class GzipRoute(APIRoute): - def get_route_handler(self) -> Callable: - original_route_handler = super().get_route_handler() - - async def custom_route_handler(request: Request) -> Response: - request = GzipRequest(request.scope, request.receive) - return await original_route_handler(request) - - return custom_route_handler - - -app = FastAPI() -app.router.route_class = GzipRoute - - -@app.post("/sum") -async def sum_numbers(numbers: List[int] = Body()): - return {"sum": sum(numbers)} diff --git a/docs_src/custom_request_and_route/tutorial001_an.py b/docs_src/custom_request_and_route/tutorial001_an.py deleted file mode 100644 index 6224ba8254..0000000000 --- a/docs_src/custom_request_and_route/tutorial001_an.py +++ /dev/null @@ -1,36 +0,0 @@ -import gzip -from typing import Callable, List - -from fastapi import Body, FastAPI, Request, Response -from fastapi.routing import APIRoute -from typing_extensions import Annotated - - -class GzipRequest(Request): - async def body(self) -> bytes: - if not hasattr(self, "_body"): - body = await super().body() - if "gzip" in self.headers.getlist("Content-Encoding"): - body = gzip.decompress(body) - self._body = body - return self._body - - -class GzipRoute(APIRoute): - def get_route_handler(self) -> Callable: - original_route_handler = super().get_route_handler() - - async def custom_route_handler(request: Request) -> Response: - request = GzipRequest(request.scope, request.receive) - return await original_route_handler(request) - - return custom_route_handler - - -app = FastAPI() -app.router.route_class = GzipRoute - - -@app.post("/sum") -async def sum_numbers(numbers: Annotated[List[int], Body()]): - return {"sum": sum(numbers)} diff --git a/docs_src/custom_request_and_route/tutorial002.py b/docs_src/custom_request_and_route/tutorial002.py deleted file mode 100644 index cee4a95f08..0000000000 --- a/docs_src/custom_request_and_route/tutorial002.py +++ /dev/null @@ -1,29 +0,0 @@ -from typing import Callable, List - -from fastapi import Body, FastAPI, HTTPException, Request, Response -from fastapi.exceptions import RequestValidationError -from fastapi.routing import APIRoute - - -class ValidationErrorLoggingRoute(APIRoute): - def get_route_handler(self) -> Callable: - original_route_handler = super().get_route_handler() - - async def custom_route_handler(request: Request) -> Response: - try: - return await original_route_handler(request) - except RequestValidationError as exc: - body = await request.body() - detail = {"errors": exc.errors(), "body": body.decode()} - raise HTTPException(status_code=422, detail=detail) - - return custom_route_handler - - -app = FastAPI() -app.router.route_class = ValidationErrorLoggingRoute - - -@app.post("/") -async def sum_numbers(numbers: List[int] = Body()): - return sum(numbers) diff --git a/docs_src/custom_request_and_route/tutorial002_an.py b/docs_src/custom_request_and_route/tutorial002_an.py deleted file mode 100644 index 127f7a9ce0..0000000000 --- a/docs_src/custom_request_and_route/tutorial002_an.py +++ /dev/null @@ -1,30 +0,0 @@ -from typing import Callable, List - -from fastapi import Body, FastAPI, HTTPException, Request, Response -from fastapi.exceptions import RequestValidationError -from fastapi.routing import APIRoute -from typing_extensions import Annotated - - -class ValidationErrorLoggingRoute(APIRoute): - def get_route_handler(self) -> Callable: - original_route_handler = super().get_route_handler() - - async def custom_route_handler(request: Request) -> Response: - try: - return await original_route_handler(request) - except RequestValidationError as exc: - body = await request.body() - detail = {"errors": exc.errors(), "body": body.decode()} - raise HTTPException(status_code=422, detail=detail) - - return custom_route_handler - - -app = FastAPI() -app.router.route_class = ValidationErrorLoggingRoute - - -@app.post("/") -async def sum_numbers(numbers: Annotated[List[int], Body()]): - return sum(numbers) diff --git a/docs_src/custom_request_and_route/tutorial003.py b/docs_src/custom_request_and_route/tutorial003_py39.py similarity index 100% rename from docs_src/custom_request_and_route/tutorial003.py rename to docs_src/custom_request_and_route/tutorial003_py39.py diff --git a/docs_src/custom_response/tutorial001.py b/docs_src/custom_response/tutorial001_py39.py similarity index 100% rename from docs_src/custom_response/tutorial001.py rename to docs_src/custom_response/tutorial001_py39.py diff --git a/docs_src/custom_response/tutorial001b.py b/docs_src/custom_response/tutorial001b_py39.py similarity index 100% rename from docs_src/custom_response/tutorial001b.py rename to docs_src/custom_response/tutorial001b_py39.py diff --git a/docs_src/custom_response/tutorial002.py b/docs_src/custom_response/tutorial002_py39.py similarity index 100% rename from docs_src/custom_response/tutorial002.py rename to docs_src/custom_response/tutorial002_py39.py diff --git a/docs_src/custom_response/tutorial003.py b/docs_src/custom_response/tutorial003_py39.py similarity index 100% rename from docs_src/custom_response/tutorial003.py rename to docs_src/custom_response/tutorial003_py39.py diff --git a/docs_src/custom_response/tutorial004.py b/docs_src/custom_response/tutorial004_py39.py similarity index 100% rename from docs_src/custom_response/tutorial004.py rename to docs_src/custom_response/tutorial004_py39.py diff --git a/docs_src/custom_response/tutorial005.py b/docs_src/custom_response/tutorial005_py39.py similarity index 100% rename from docs_src/custom_response/tutorial005.py rename to docs_src/custom_response/tutorial005_py39.py diff --git a/docs_src/custom_response/tutorial006.py b/docs_src/custom_response/tutorial006_py39.py similarity index 100% rename from docs_src/custom_response/tutorial006.py rename to docs_src/custom_response/tutorial006_py39.py diff --git a/docs_src/custom_response/tutorial006b.py b/docs_src/custom_response/tutorial006b_py39.py similarity index 100% rename from docs_src/custom_response/tutorial006b.py rename to docs_src/custom_response/tutorial006b_py39.py diff --git a/docs_src/custom_response/tutorial006c.py b/docs_src/custom_response/tutorial006c_py39.py similarity index 100% rename from docs_src/custom_response/tutorial006c.py rename to docs_src/custom_response/tutorial006c_py39.py diff --git a/docs_src/custom_response/tutorial007.py b/docs_src/custom_response/tutorial007_py39.py similarity index 100% rename from docs_src/custom_response/tutorial007.py rename to docs_src/custom_response/tutorial007_py39.py diff --git a/docs_src/custom_response/tutorial008.py b/docs_src/custom_response/tutorial008_py39.py similarity index 100% rename from docs_src/custom_response/tutorial008.py rename to docs_src/custom_response/tutorial008_py39.py diff --git a/docs_src/custom_response/tutorial009.py b/docs_src/custom_response/tutorial009_py39.py similarity index 100% rename from docs_src/custom_response/tutorial009.py rename to docs_src/custom_response/tutorial009_py39.py diff --git a/docs_src/custom_response/tutorial009b.py b/docs_src/custom_response/tutorial009b_py39.py similarity index 100% rename from docs_src/custom_response/tutorial009b.py rename to docs_src/custom_response/tutorial009b_py39.py diff --git a/docs_src/custom_response/tutorial009c.py b/docs_src/custom_response/tutorial009c_py39.py similarity index 100% rename from docs_src/custom_response/tutorial009c.py rename to docs_src/custom_response/tutorial009c_py39.py diff --git a/docs_src/custom_response/tutorial010.py b/docs_src/custom_response/tutorial010_py39.py similarity index 100% rename from docs_src/custom_response/tutorial010.py rename to docs_src/custom_response/tutorial010_py39.py diff --git a/docs_src/dataclasses/tutorial001.py b/docs_src/dataclasses/tutorial001_py39.py similarity index 100% rename from docs_src/dataclasses/tutorial001.py rename to docs_src/dataclasses/tutorial001_py39.py diff --git a/docs_src/dataclasses/tutorial002.py b/docs_src/dataclasses/tutorial002.py deleted file mode 100644 index ece2f150cc..0000000000 --- a/docs_src/dataclasses/tutorial002.py +++ /dev/null @@ -1,26 +0,0 @@ -from dataclasses import dataclass, field -from typing import List, Union - -from fastapi import FastAPI - - -@dataclass -class Item: - name: str - price: float - tags: List[str] = field(default_factory=list) - description: Union[str, None] = None - tax: Union[float, None] = None - - -app = FastAPI() - - -@app.get("/items/next", response_model=Item) -async def read_next_item(): - return { - "name": "Island In The Moon", - "price": 12.99, - "description": "A place to be playin' and havin' fun", - "tags": ["breater"], - } diff --git a/docs_src/dataclasses/tutorial003.py b/docs_src/dataclasses/tutorial003.py deleted file mode 100644 index c613155133..0000000000 --- a/docs_src/dataclasses/tutorial003.py +++ /dev/null @@ -1,55 +0,0 @@ -from dataclasses import field # (1) -from typing import List, Union - -from fastapi import FastAPI -from pydantic.dataclasses import dataclass # (2) - - -@dataclass -class Item: - name: str - description: Union[str, None] = None - - -@dataclass -class Author: - name: str - items: List[Item] = field(default_factory=list) # (3) - - -app = FastAPI() - - -@app.post("/authors/{author_id}/items/", response_model=Author) # (4) -async def create_author_items(author_id: str, items: List[Item]): # (5) - return {"name": author_id, "items": items} # (6) - - -@app.get("/authors/", response_model=List[Author]) # (7) -def get_authors(): # (8) - return [ # (9) - { - "name": "Breaters", - "items": [ - { - "name": "Island In The Moon", - "description": "A place to be playin' and havin' fun", - }, - {"name": "Holy Buddies"}, - ], - }, - { - "name": "System of an Up", - "items": [ - { - "name": "Salt", - "description": "The kombucha mushroom people's favorite", - }, - {"name": "Pad Thai"}, - { - "name": "Lonely Night", - "description": "The mostests lonliest nightiest of allest", - }, - ], - }, - ] diff --git a/docs_src/debugging/tutorial001.py b/docs_src/debugging/tutorial001_py39.py similarity index 100% rename from docs_src/debugging/tutorial001.py rename to docs_src/debugging/tutorial001_py39.py diff --git a/docs_src/dependencies/tutorial001_02_an.py b/docs_src/dependencies/tutorial001_02_an.py deleted file mode 100644 index 455d60c822..0000000000 --- a/docs_src/dependencies/tutorial001_02_an.py +++ /dev/null @@ -1,25 +0,0 @@ -from typing import Union - -from fastapi import Depends, FastAPI -from typing_extensions import Annotated - -app = FastAPI() - - -async def common_parameters( - q: Union[str, None] = None, skip: int = 0, limit: int = 100 -): - return {"q": q, "skip": skip, "limit": limit} - - -CommonsDep = Annotated[dict, Depends(common_parameters)] - - -@app.get("/items/") -async def read_items(commons: CommonsDep): - return commons - - -@app.get("/users/") -async def read_users(commons: CommonsDep): - return commons diff --git a/docs_src/dependencies/tutorial001_an.py b/docs_src/dependencies/tutorial001_an.py deleted file mode 100644 index 81e24fe86c..0000000000 --- a/docs_src/dependencies/tutorial001_an.py +++ /dev/null @@ -1,22 +0,0 @@ -from typing import Union - -from fastapi import Depends, FastAPI -from typing_extensions import Annotated - -app = FastAPI() - - -async def common_parameters( - q: Union[str, None] = None, skip: int = 0, limit: int = 100 -): - return {"q": q, "skip": skip, "limit": limit} - - -@app.get("/items/") -async def read_items(commons: Annotated[dict, Depends(common_parameters)]): - return commons - - -@app.get("/users/") -async def read_users(commons: Annotated[dict, Depends(common_parameters)]): - return commons diff --git a/docs_src/dependencies/tutorial001.py b/docs_src/dependencies/tutorial001_py39.py similarity index 100% rename from docs_src/dependencies/tutorial001.py rename to docs_src/dependencies/tutorial001_py39.py diff --git a/docs_src/dependencies/tutorial002_an.py b/docs_src/dependencies/tutorial002_an.py deleted file mode 100644 index 964ccf66ca..0000000000 --- a/docs_src/dependencies/tutorial002_an.py +++ /dev/null @@ -1,26 +0,0 @@ -from typing import Union - -from fastapi import Depends, FastAPI -from typing_extensions import Annotated - -app = FastAPI() - - -fake_items_db = [{"item_name": "Foo"}, {"item_name": "Bar"}, {"item_name": "Baz"}] - - -class CommonQueryParams: - def __init__(self, q: Union[str, None] = None, skip: int = 0, limit: int = 100): - self.q = q - self.skip = skip - self.limit = limit - - -@app.get("/items/") -async def read_items(commons: Annotated[CommonQueryParams, Depends(CommonQueryParams)]): - response = {} - if commons.q: - response.update({"q": commons.q}) - items = fake_items_db[commons.skip : commons.skip + commons.limit] - response.update({"items": items}) - return response diff --git a/docs_src/dependencies/tutorial002.py b/docs_src/dependencies/tutorial002_py39.py similarity index 100% rename from docs_src/dependencies/tutorial002.py rename to docs_src/dependencies/tutorial002_py39.py diff --git a/docs_src/dependencies/tutorial003_an.py b/docs_src/dependencies/tutorial003_an.py deleted file mode 100644 index ba8e9f7174..0000000000 --- a/docs_src/dependencies/tutorial003_an.py +++ /dev/null @@ -1,26 +0,0 @@ -from typing import Any, Union - -from fastapi import Depends, FastAPI -from typing_extensions import Annotated - -app = FastAPI() - - -fake_items_db = [{"item_name": "Foo"}, {"item_name": "Bar"}, {"item_name": "Baz"}] - - -class CommonQueryParams: - def __init__(self, q: Union[str, None] = None, skip: int = 0, limit: int = 100): - self.q = q - self.skip = skip - self.limit = limit - - -@app.get("/items/") -async def read_items(commons: Annotated[Any, Depends(CommonQueryParams)]): - response = {} - if commons.q: - response.update({"q": commons.q}) - items = fake_items_db[commons.skip : commons.skip + commons.limit] - response.update({"items": items}) - return response diff --git a/docs_src/dependencies/tutorial003.py b/docs_src/dependencies/tutorial003_py39.py similarity index 100% rename from docs_src/dependencies/tutorial003.py rename to docs_src/dependencies/tutorial003_py39.py diff --git a/docs_src/dependencies/tutorial004_an.py b/docs_src/dependencies/tutorial004_an.py deleted file mode 100644 index 78881a354c..0000000000 --- a/docs_src/dependencies/tutorial004_an.py +++ /dev/null @@ -1,26 +0,0 @@ -from typing import Union - -from fastapi import Depends, FastAPI -from typing_extensions import Annotated - -app = FastAPI() - - -fake_items_db = [{"item_name": "Foo"}, {"item_name": "Bar"}, {"item_name": "Baz"}] - - -class CommonQueryParams: - def __init__(self, q: Union[str, None] = None, skip: int = 0, limit: int = 100): - self.q = q - self.skip = skip - self.limit = limit - - -@app.get("/items/") -async def read_items(commons: Annotated[CommonQueryParams, Depends()]): - response = {} - if commons.q: - response.update({"q": commons.q}) - items = fake_items_db[commons.skip : commons.skip + commons.limit] - response.update({"items": items}) - return response diff --git a/docs_src/dependencies/tutorial004.py b/docs_src/dependencies/tutorial004_py39.py similarity index 100% rename from docs_src/dependencies/tutorial004.py rename to docs_src/dependencies/tutorial004_py39.py diff --git a/docs_src/dependencies/tutorial005_an.py b/docs_src/dependencies/tutorial005_an.py deleted file mode 100644 index 1d78c17a2a..0000000000 --- a/docs_src/dependencies/tutorial005_an.py +++ /dev/null @@ -1,26 +0,0 @@ -from typing import Union - -from fastapi import Cookie, Depends, FastAPI -from typing_extensions import Annotated - -app = FastAPI() - - -def query_extractor(q: Union[str, None] = None): - return q - - -def query_or_cookie_extractor( - q: Annotated[str, Depends(query_extractor)], - last_query: Annotated[Union[str, None], Cookie()] = None, -): - if not q: - return last_query - return q - - -@app.get("/items/") -async def read_query( - query_or_default: Annotated[str, Depends(query_or_cookie_extractor)], -): - return {"q_or_cookie": query_or_default} diff --git a/docs_src/dependencies/tutorial005.py b/docs_src/dependencies/tutorial005_py39.py similarity index 100% rename from docs_src/dependencies/tutorial005.py rename to docs_src/dependencies/tutorial005_py39.py diff --git a/docs_src/dependencies/tutorial006_an.py b/docs_src/dependencies/tutorial006_an.py deleted file mode 100644 index 5aaea04d16..0000000000 --- a/docs_src/dependencies/tutorial006_an.py +++ /dev/null @@ -1,20 +0,0 @@ -from fastapi import Depends, FastAPI, Header, HTTPException -from typing_extensions import Annotated - -app = FastAPI() - - -async def verify_token(x_token: Annotated[str, Header()]): - if x_token != "fake-super-secret-token": - raise HTTPException(status_code=400, detail="X-Token header invalid") - - -async def verify_key(x_key: Annotated[str, Header()]): - if x_key != "fake-super-secret-key": - raise HTTPException(status_code=400, detail="X-Key header invalid") - return x_key - - -@app.get("/items/", dependencies=[Depends(verify_token), Depends(verify_key)]) -async def read_items(): - return [{"item": "Foo"}, {"item": "Bar"}] diff --git a/docs_src/dependencies/tutorial006.py b/docs_src/dependencies/tutorial006_py39.py similarity index 100% rename from docs_src/dependencies/tutorial006.py rename to docs_src/dependencies/tutorial006_py39.py diff --git a/docs_src/dependencies/tutorial007.py b/docs_src/dependencies/tutorial007_py39.py similarity index 100% rename from docs_src/dependencies/tutorial007.py rename to docs_src/dependencies/tutorial007_py39.py diff --git a/docs_src/dependencies/tutorial008_an.py b/docs_src/dependencies/tutorial008_an.py deleted file mode 100644 index 2de86f042d..0000000000 --- a/docs_src/dependencies/tutorial008_an.py +++ /dev/null @@ -1,26 +0,0 @@ -from fastapi import Depends -from typing_extensions import Annotated - - -async def dependency_a(): - dep_a = generate_dep_a() - try: - yield dep_a - finally: - dep_a.close() - - -async def dependency_b(dep_a: Annotated[DepA, Depends(dependency_a)]): - dep_b = generate_dep_b() - try: - yield dep_b - finally: - dep_b.close(dep_a) - - -async def dependency_c(dep_b: Annotated[DepB, Depends(dependency_b)]): - dep_c = generate_dep_c() - try: - yield dep_c - finally: - dep_c.close(dep_b) diff --git a/docs_src/dependencies/tutorial008.py b/docs_src/dependencies/tutorial008_py39.py similarity index 100% rename from docs_src/dependencies/tutorial008.py rename to docs_src/dependencies/tutorial008_py39.py diff --git a/docs_src/dependencies/tutorial008b_an.py b/docs_src/dependencies/tutorial008b_an.py deleted file mode 100644 index 84d8f12c14..0000000000 --- a/docs_src/dependencies/tutorial008b_an.py +++ /dev/null @@ -1,31 +0,0 @@ -from fastapi import Depends, FastAPI, HTTPException -from typing_extensions import Annotated - -app = FastAPI() - - -data = { - "plumbus": {"description": "Freshly pickled plumbus", "owner": "Morty"}, - "portal-gun": {"description": "Gun to create portals", "owner": "Rick"}, -} - - -class OwnerError(Exception): - pass - - -def get_username(): - try: - yield "Rick" - except OwnerError as e: - raise HTTPException(status_code=400, detail=f"Owner error: {e}") - - -@app.get("/items/{item_id}") -def get_item(item_id: str, username: Annotated[str, Depends(get_username)]): - if item_id not in data: - raise HTTPException(status_code=404, detail="Item not found") - item = data[item_id] - if item["owner"] != username: - raise OwnerError(username) - return item diff --git a/docs_src/dependencies/tutorial008b.py b/docs_src/dependencies/tutorial008b_py39.py similarity index 100% rename from docs_src/dependencies/tutorial008b.py rename to docs_src/dependencies/tutorial008b_py39.py diff --git a/docs_src/dependencies/tutorial008c_an.py b/docs_src/dependencies/tutorial008c_an.py deleted file mode 100644 index 94f59f9aa6..0000000000 --- a/docs_src/dependencies/tutorial008c_an.py +++ /dev/null @@ -1,28 +0,0 @@ -from fastapi import Depends, FastAPI, HTTPException -from typing_extensions import Annotated - -app = FastAPI() - - -class InternalError(Exception): - pass - - -def get_username(): - try: - yield "Rick" - except InternalError: - print("Oops, we didn't raise again, Britney 😱") - - -@app.get("/items/{item_id}") -def get_item(item_id: str, username: Annotated[str, Depends(get_username)]): - if item_id == "portal-gun": - raise InternalError( - f"The portal gun is too dangerous to be owned by {username}" - ) - if item_id != "plumbus": - raise HTTPException( - status_code=404, detail="Item not found, there's only a plumbus here" - ) - return item_id diff --git a/docs_src/dependencies/tutorial008c.py b/docs_src/dependencies/tutorial008c_py39.py similarity index 100% rename from docs_src/dependencies/tutorial008c.py rename to docs_src/dependencies/tutorial008c_py39.py diff --git a/docs_src/dependencies/tutorial008d_an.py b/docs_src/dependencies/tutorial008d_an.py deleted file mode 100644 index c354245744..0000000000 --- a/docs_src/dependencies/tutorial008d_an.py +++ /dev/null @@ -1,29 +0,0 @@ -from fastapi import Depends, FastAPI, HTTPException -from typing_extensions import Annotated - -app = FastAPI() - - -class InternalError(Exception): - pass - - -def get_username(): - try: - yield "Rick" - except InternalError: - print("We don't swallow the internal error here, we raise again 😎") - raise - - -@app.get("/items/{item_id}") -def get_item(item_id: str, username: Annotated[str, Depends(get_username)]): - if item_id == "portal-gun": - raise InternalError( - f"The portal gun is too dangerous to be owned by {username}" - ) - if item_id != "plumbus": - raise HTTPException( - status_code=404, detail="Item not found, there's only a plumbus here" - ) - return item_id diff --git a/docs_src/dependencies/tutorial008d.py b/docs_src/dependencies/tutorial008d_py39.py similarity index 100% rename from docs_src/dependencies/tutorial008d.py rename to docs_src/dependencies/tutorial008d_py39.py diff --git a/docs_src/dependencies/tutorial008e_an.py b/docs_src/dependencies/tutorial008e_an.py deleted file mode 100644 index c8a0af2b3b..0000000000 --- a/docs_src/dependencies/tutorial008e_an.py +++ /dev/null @@ -1,16 +0,0 @@ -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 diff --git a/docs_src/dependencies/tutorial008e.py b/docs_src/dependencies/tutorial008e_py39.py similarity index 100% rename from docs_src/dependencies/tutorial008e.py rename to docs_src/dependencies/tutorial008e_py39.py diff --git a/docs_src/dependencies/tutorial009.py b/docs_src/dependencies/tutorial009.py deleted file mode 100644 index 8472f642de..0000000000 --- a/docs_src/dependencies/tutorial009.py +++ /dev/null @@ -1,25 +0,0 @@ -from fastapi import Depends - - -async def dependency_a(): - dep_a = generate_dep_a() - try: - yield dep_a - finally: - dep_a.close() - - -async def dependency_b(dep_a=Depends(dependency_a)): - dep_b = generate_dep_b() - try: - yield dep_b - finally: - dep_b.close(dep_a) - - -async def dependency_c(dep_b=Depends(dependency_b)): - dep_c = generate_dep_c() - try: - yield dep_c - finally: - dep_c.close(dep_b) diff --git a/docs_src/dependencies/tutorial010.py b/docs_src/dependencies/tutorial010_py39.py similarity index 100% rename from docs_src/dependencies/tutorial010.py rename to docs_src/dependencies/tutorial010_py39.py diff --git a/docs_src/dependencies/tutorial011_an.py b/docs_src/dependencies/tutorial011_an.py deleted file mode 100644 index 6c13d9033f..0000000000 --- a/docs_src/dependencies/tutorial011_an.py +++ /dev/null @@ -1,22 +0,0 @@ -from fastapi import Depends, FastAPI -from typing_extensions import Annotated - -app = FastAPI() - - -class FixedContentQueryChecker: - def __init__(self, fixed_content: str): - self.fixed_content = fixed_content - - def __call__(self, q: str = ""): - if q: - return self.fixed_content in q - return False - - -checker = FixedContentQueryChecker("bar") - - -@app.get("/query-checker/") -async def read_query_check(fixed_content_included: Annotated[bool, Depends(checker)]): - return {"fixed_content_in_query": fixed_content_included} diff --git a/docs_src/dependencies/tutorial011.py b/docs_src/dependencies/tutorial011_py39.py similarity index 100% rename from docs_src/dependencies/tutorial011.py rename to docs_src/dependencies/tutorial011_py39.py diff --git a/docs_src/dependencies/tutorial012_an.py b/docs_src/dependencies/tutorial012_an.py deleted file mode 100644 index 7541e6bf41..0000000000 --- a/docs_src/dependencies/tutorial012_an.py +++ /dev/null @@ -1,26 +0,0 @@ -from fastapi import Depends, FastAPI, Header, HTTPException -from typing_extensions import Annotated - - -async def verify_token(x_token: Annotated[str, Header()]): - if x_token != "fake-super-secret-token": - raise HTTPException(status_code=400, detail="X-Token header invalid") - - -async def verify_key(x_key: Annotated[str, Header()]): - if x_key != "fake-super-secret-key": - raise HTTPException(status_code=400, detail="X-Key header invalid") - return x_key - - -app = FastAPI(dependencies=[Depends(verify_token), Depends(verify_key)]) - - -@app.get("/items/") -async def read_items(): - return [{"item": "Portal Gun"}, {"item": "Plumbus"}] - - -@app.get("/users/") -async def read_users(): - return [{"username": "Rick"}, {"username": "Morty"}] diff --git a/docs_src/dependencies/tutorial012_an_py39.py b/docs_src/dependencies/tutorial012_an_py39.py index 7541e6bf41..6503591fc3 100644 --- a/docs_src/dependencies/tutorial012_an_py39.py +++ b/docs_src/dependencies/tutorial012_an_py39.py @@ -1,5 +1,6 @@ +from typing import Annotated + from fastapi import Depends, FastAPI, Header, HTTPException -from typing_extensions import Annotated async def verify_token(x_token: Annotated[str, Header()]): diff --git a/docs_src/dependencies/tutorial012.py b/docs_src/dependencies/tutorial012_py39.py similarity index 100% rename from docs_src/dependencies/tutorial012.py rename to docs_src/dependencies/tutorial012_py39.py diff --git a/docs_src/dependency_testing/tutorial001_an.py b/docs_src/dependency_testing/tutorial001_an.py deleted file mode 100644 index 4c76a87ff5..0000000000 --- a/docs_src/dependency_testing/tutorial001_an.py +++ /dev/null @@ -1,60 +0,0 @@ -from typing import Union - -from fastapi import Depends, FastAPI -from fastapi.testclient import TestClient -from typing_extensions import Annotated - -app = FastAPI() - - -async def common_parameters( - q: Union[str, None] = None, skip: int = 0, limit: int = 100 -): - return {"q": q, "skip": skip, "limit": limit} - - -@app.get("/items/") -async def read_items(commons: Annotated[dict, Depends(common_parameters)]): - return {"message": "Hello Items!", "params": commons} - - -@app.get("/users/") -async def read_users(commons: Annotated[dict, Depends(common_parameters)]): - return {"message": "Hello Users!", "params": commons} - - -client = TestClient(app) - - -async def override_dependency(q: Union[str, None] = None): - return {"q": q, "skip": 5, "limit": 10} - - -app.dependency_overrides[common_parameters] = override_dependency - - -def test_override_in_items(): - response = client.get("/items/") - assert response.status_code == 200 - assert response.json() == { - "message": "Hello Items!", - "params": {"q": None, "skip": 5, "limit": 10}, - } - - -def test_override_in_items_with_q(): - response = client.get("/items/?q=foo") - assert response.status_code == 200 - assert response.json() == { - "message": "Hello Items!", - "params": {"q": "foo", "skip": 5, "limit": 10}, - } - - -def test_override_in_items_with_params(): - response = client.get("/items/?q=foo&skip=100&limit=200") - assert response.status_code == 200 - assert response.json() == { - "message": "Hello Items!", - "params": {"q": "foo", "skip": 5, "limit": 10}, - } diff --git a/docs_src/dependency_testing/tutorial001.py b/docs_src/dependency_testing/tutorial001_py39.py similarity index 100% rename from docs_src/dependency_testing/tutorial001.py rename to docs_src/dependency_testing/tutorial001_py39.py diff --git a/docs_src/encoder/tutorial001.py b/docs_src/encoder/tutorial001_py39.py similarity index 100% rename from docs_src/encoder/tutorial001.py rename to docs_src/encoder/tutorial001_py39.py diff --git a/docs_src/events/tutorial001.py b/docs_src/events/tutorial001_py39.py similarity index 100% rename from docs_src/events/tutorial001.py rename to docs_src/events/tutorial001_py39.py diff --git a/docs_src/events/tutorial002.py b/docs_src/events/tutorial002_py39.py similarity index 100% rename from docs_src/events/tutorial002.py rename to docs_src/events/tutorial002_py39.py diff --git a/docs_src/events/tutorial003.py b/docs_src/events/tutorial003_py39.py similarity index 100% rename from docs_src/events/tutorial003.py rename to docs_src/events/tutorial003_py39.py diff --git a/docs_src/extending_openapi/tutorial001.py b/docs_src/extending_openapi/tutorial001_py39.py similarity index 100% rename from docs_src/extending_openapi/tutorial001.py rename to docs_src/extending_openapi/tutorial001_py39.py diff --git a/docs_src/extra_data_types/tutorial001_an.py b/docs_src/extra_data_types/tutorial001_an.py deleted file mode 100644 index 257d0c7c86..0000000000 --- a/docs_src/extra_data_types/tutorial001_an.py +++ /dev/null @@ -1,29 +0,0 @@ -from datetime import datetime, time, timedelta -from typing import Union -from uuid import UUID - -from fastapi import Body, FastAPI -from typing_extensions import Annotated - -app = FastAPI() - - -@app.put("/items/{item_id}") -async def read_items( - item_id: UUID, - start_datetime: Annotated[datetime, Body()], - end_datetime: Annotated[datetime, Body()], - process_after: Annotated[timedelta, Body()], - repeat_at: Annotated[Union[time, None], Body()] = None, -): - start_process = start_datetime + process_after - duration = end_datetime - start_process - return { - "item_id": item_id, - "start_datetime": start_datetime, - "end_datetime": end_datetime, - "process_after": process_after, - "repeat_at": repeat_at, - "start_process": start_process, - "duration": duration, - } diff --git a/docs_src/extra_data_types/tutorial001.py b/docs_src/extra_data_types/tutorial001_py39.py similarity index 100% rename from docs_src/extra_data_types/tutorial001.py rename to docs_src/extra_data_types/tutorial001_py39.py diff --git a/docs_src/extra_models/tutorial001.py b/docs_src/extra_models/tutorial001_py39.py similarity index 100% rename from docs_src/extra_models/tutorial001.py rename to docs_src/extra_models/tutorial001_py39.py diff --git a/docs_src/extra_models/tutorial002.py b/docs_src/extra_models/tutorial002_py39.py similarity index 100% rename from docs_src/extra_models/tutorial002.py rename to docs_src/extra_models/tutorial002_py39.py diff --git a/docs_src/extra_models/tutorial003.py b/docs_src/extra_models/tutorial003_py39.py similarity index 100% rename from docs_src/extra_models/tutorial003.py rename to docs_src/extra_models/tutorial003_py39.py diff --git a/docs_src/extra_models/tutorial004.py b/docs_src/extra_models/tutorial004.py deleted file mode 100644 index a8e0f7af5a..0000000000 --- a/docs_src/extra_models/tutorial004.py +++ /dev/null @@ -1,22 +0,0 @@ -from typing import List - -from fastapi import FastAPI -from pydantic import BaseModel - -app = FastAPI() - - -class Item(BaseModel): - name: str - description: str - - -items = [ - {"name": "Foo", "description": "There comes my hero"}, - {"name": "Red", "description": "It's my aeroplane"}, -] - - -@app.get("/items/", response_model=List[Item]) -async def read_items(): - return items diff --git a/docs_src/extra_models/tutorial005.py b/docs_src/extra_models/tutorial005.py deleted file mode 100644 index a81cbc2c58..0000000000 --- a/docs_src/extra_models/tutorial005.py +++ /dev/null @@ -1,10 +0,0 @@ -from typing import Dict - -from fastapi import FastAPI - -app = FastAPI() - - -@app.get("/keyword-weights/", response_model=Dict[str, float]) -async def read_keyword_weights(): - return {"foo": 2.3, "bar": 3.4} diff --git a/docs_src/first_steps/tutorial001.py b/docs_src/first_steps/tutorial001_py39.py similarity index 100% rename from docs_src/first_steps/tutorial001.py rename to docs_src/first_steps/tutorial001_py39.py diff --git a/docs_src/first_steps/tutorial002.py b/docs_src/first_steps/tutorial002.py deleted file mode 100644 index ca7d48cff9..0000000000 --- a/docs_src/first_steps/tutorial002.py +++ /dev/null @@ -1,8 +0,0 @@ -from fastapi import FastAPI - -my_awesome_api = FastAPI() - - -@my_awesome_api.get("/") -async def root(): - return {"message": "Hello World"} diff --git a/docs_src/first_steps/tutorial003.py b/docs_src/first_steps/tutorial003_py39.py similarity index 100% rename from docs_src/first_steps/tutorial003.py rename to docs_src/first_steps/tutorial003_py39.py diff --git a/docs_src/generate_clients/tutorial001.py b/docs_src/generate_clients/tutorial001.py deleted file mode 100644 index 2d1f91bc6c..0000000000 --- a/docs_src/generate_clients/tutorial001.py +++ /dev/null @@ -1,28 +0,0 @@ -from typing import List - -from fastapi import FastAPI -from pydantic import BaseModel - -app = FastAPI() - - -class Item(BaseModel): - name: str - price: float - - -class ResponseMessage(BaseModel): - message: str - - -@app.post("/items/", response_model=ResponseMessage) -async def create_item(item: Item): - return {"message": "item received"} - - -@app.get("/items/", response_model=List[Item]) -async def get_items(): - return [ - {"name": "Plumbus", "price": 3}, - {"name": "Portal Gun", "price": 9001}, - ] diff --git a/docs_src/generate_clients/tutorial002.py b/docs_src/generate_clients/tutorial002.py deleted file mode 100644 index bd80449af9..0000000000 --- a/docs_src/generate_clients/tutorial002.py +++ /dev/null @@ -1,38 +0,0 @@ -from typing import List - -from fastapi import FastAPI -from pydantic import BaseModel - -app = FastAPI() - - -class Item(BaseModel): - name: str - price: float - - -class ResponseMessage(BaseModel): - message: str - - -class User(BaseModel): - username: str - email: str - - -@app.post("/items/", response_model=ResponseMessage, tags=["items"]) -async def create_item(item: Item): - return {"message": "Item received"} - - -@app.get("/items/", response_model=List[Item], tags=["items"]) -async def get_items(): - return [ - {"name": "Plumbus", "price": 3}, - {"name": "Portal Gun", "price": 9001}, - ] - - -@app.post("/users/", response_model=ResponseMessage, tags=["users"]) -async def create_user(user: User): - return {"message": "User received"} diff --git a/docs_src/generate_clients/tutorial003.py b/docs_src/generate_clients/tutorial003.py deleted file mode 100644 index 49eab73a1b..0000000000 --- a/docs_src/generate_clients/tutorial003.py +++ /dev/null @@ -1,44 +0,0 @@ -from typing import List - -from fastapi import FastAPI -from fastapi.routing import APIRoute -from pydantic import BaseModel - - -def custom_generate_unique_id(route: APIRoute): - return f"{route.tags[0]}-{route.name}" - - -app = FastAPI(generate_unique_id_function=custom_generate_unique_id) - - -class Item(BaseModel): - name: str - price: float - - -class ResponseMessage(BaseModel): - message: str - - -class User(BaseModel): - username: str - email: str - - -@app.post("/items/", response_model=ResponseMessage, tags=["items"]) -async def create_item(item: Item): - return {"message": "Item received"} - - -@app.get("/items/", response_model=List[Item], tags=["items"]) -async def get_items(): - return [ - {"name": "Plumbus", "price": 3}, - {"name": "Portal Gun", "price": 9001}, - ] - - -@app.post("/users/", response_model=ResponseMessage, tags=["users"]) -async def create_user(user: User): - return {"message": "User received"} diff --git a/docs_src/generate_clients/tutorial004.py b/docs_src/generate_clients/tutorial004_py39.py similarity index 100% rename from docs_src/generate_clients/tutorial004.py rename to docs_src/generate_clients/tutorial004_py39.py diff --git a/docs_src/graphql/tutorial001.py b/docs_src/graphql/tutorial001_py39.py similarity index 100% rename from docs_src/graphql/tutorial001.py rename to docs_src/graphql/tutorial001_py39.py diff --git a/docs_src/handling_errors/tutorial001.py b/docs_src/handling_errors/tutorial001_py39.py similarity index 100% rename from docs_src/handling_errors/tutorial001.py rename to docs_src/handling_errors/tutorial001_py39.py diff --git a/docs_src/handling_errors/tutorial002.py b/docs_src/handling_errors/tutorial002_py39.py similarity index 100% rename from docs_src/handling_errors/tutorial002.py rename to docs_src/handling_errors/tutorial002_py39.py diff --git a/docs_src/handling_errors/tutorial003.py b/docs_src/handling_errors/tutorial003_py39.py similarity index 100% rename from docs_src/handling_errors/tutorial003.py rename to docs_src/handling_errors/tutorial003_py39.py diff --git a/docs_src/handling_errors/tutorial004.py b/docs_src/handling_errors/tutorial004_py39.py similarity index 100% rename from docs_src/handling_errors/tutorial004.py rename to docs_src/handling_errors/tutorial004_py39.py diff --git a/docs_src/handling_errors/tutorial005.py b/docs_src/handling_errors/tutorial005_py39.py similarity index 100% rename from docs_src/handling_errors/tutorial005.py rename to docs_src/handling_errors/tutorial005_py39.py diff --git a/docs_src/handling_errors/tutorial006.py b/docs_src/handling_errors/tutorial006_py39.py similarity index 100% rename from docs_src/handling_errors/tutorial006.py rename to docs_src/handling_errors/tutorial006_py39.py diff --git a/docs_src/header_param_models/tutorial001.py b/docs_src/header_param_models/tutorial001.py deleted file mode 100644 index 4caaba87b9..0000000000 --- a/docs_src/header_param_models/tutorial001.py +++ /dev/null @@ -1,19 +0,0 @@ -from typing import List, Union - -from fastapi import FastAPI, Header -from pydantic import BaseModel - -app = FastAPI() - - -class CommonHeaders(BaseModel): - host: str - save_data: bool - if_modified_since: Union[str, None] = None - traceparent: Union[str, None] = None - x_tag: List[str] = [] - - -@app.get("/items/") -async def read_items(headers: CommonHeaders = Header()): - return headers diff --git a/docs_src/header_param_models/tutorial001_an.py b/docs_src/header_param_models/tutorial001_an.py deleted file mode 100644 index b55c6b56b1..0000000000 --- a/docs_src/header_param_models/tutorial001_an.py +++ /dev/null @@ -1,20 +0,0 @@ -from typing import List, Union - -from fastapi import FastAPI, Header -from pydantic import BaseModel -from typing_extensions import Annotated - -app = FastAPI() - - -class CommonHeaders(BaseModel): - host: str - save_data: bool - if_modified_since: Union[str, None] = None - traceparent: Union[str, None] = None - x_tag: List[str] = [] - - -@app.get("/items/") -async def read_items(headers: Annotated[CommonHeaders, Header()]): - return headers diff --git a/docs_src/header_param_models/tutorial002.py b/docs_src/header_param_models/tutorial002.py deleted file mode 100644 index 3f9aac58d2..0000000000 --- a/docs_src/header_param_models/tutorial002.py +++ /dev/null @@ -1,21 +0,0 @@ -from typing import List, Union - -from fastapi import FastAPI, Header -from pydantic import BaseModel - -app = FastAPI() - - -class CommonHeaders(BaseModel): - model_config = {"extra": "forbid"} - - host: str - save_data: bool - if_modified_since: Union[str, None] = None - traceparent: Union[str, None] = None - x_tag: List[str] = [] - - -@app.get("/items/") -async def read_items(headers: CommonHeaders = Header()): - return headers diff --git a/docs_src/header_param_models/tutorial002_an.py b/docs_src/header_param_models/tutorial002_an.py deleted file mode 100644 index 771135d770..0000000000 --- a/docs_src/header_param_models/tutorial002_an.py +++ /dev/null @@ -1,22 +0,0 @@ -from typing import List, Union - -from fastapi import FastAPI, Header -from pydantic import BaseModel -from typing_extensions import Annotated - -app = FastAPI() - - -class CommonHeaders(BaseModel): - model_config = {"extra": "forbid"} - - host: str - save_data: bool - if_modified_since: Union[str, None] = None - traceparent: Union[str, None] = None - x_tag: List[str] = [] - - -@app.get("/items/") -async def read_items(headers: Annotated[CommonHeaders, Header()]): - return headers diff --git a/docs_src/header_param_models/tutorial002_pv1.py b/docs_src/header_param_models/tutorial002_pv1.py deleted file mode 100644 index 7e56cd993b..0000000000 --- a/docs_src/header_param_models/tutorial002_pv1.py +++ /dev/null @@ -1,22 +0,0 @@ -from typing import List, Union - -from fastapi import FastAPI, Header -from pydantic import BaseModel - -app = FastAPI() - - -class CommonHeaders(BaseModel): - class Config: - extra = "forbid" - - host: str - save_data: bool - if_modified_since: Union[str, None] = None - traceparent: Union[str, None] = None - x_tag: List[str] = [] - - -@app.get("/items/") -async def read_items(headers: CommonHeaders = Header()): - return headers diff --git a/docs_src/header_param_models/tutorial002_pv1_an.py b/docs_src/header_param_models/tutorial002_pv1_an.py deleted file mode 100644 index 236778231a..0000000000 --- a/docs_src/header_param_models/tutorial002_pv1_an.py +++ /dev/null @@ -1,23 +0,0 @@ -from typing import List, Union - -from fastapi import FastAPI, Header -from pydantic import BaseModel -from typing_extensions import Annotated - -app = FastAPI() - - -class CommonHeaders(BaseModel): - class Config: - extra = "forbid" - - host: str - save_data: bool - if_modified_since: Union[str, None] = None - traceparent: Union[str, None] = None - x_tag: List[str] = [] - - -@app.get("/items/") -async def read_items(headers: Annotated[CommonHeaders, Header()]): - return headers diff --git a/docs_src/header_param_models/tutorial003.py b/docs_src/header_param_models/tutorial003.py deleted file mode 100644 index dc2eb74bd1..0000000000 --- a/docs_src/header_param_models/tutorial003.py +++ /dev/null @@ -1,19 +0,0 @@ -from typing import List, Union - -from fastapi import FastAPI, Header -from pydantic import BaseModel - -app = FastAPI() - - -class CommonHeaders(BaseModel): - host: str - save_data: bool - if_modified_since: Union[str, None] = None - traceparent: Union[str, None] = None - x_tag: List[str] = [] - - -@app.get("/items/") -async def read_items(headers: CommonHeaders = Header(convert_underscores=False)): - return headers diff --git a/docs_src/header_param_models/tutorial003_an.py b/docs_src/header_param_models/tutorial003_an.py deleted file mode 100644 index e3edb11891..0000000000 --- a/docs_src/header_param_models/tutorial003_an.py +++ /dev/null @@ -1,22 +0,0 @@ -from typing import List, Union - -from fastapi import FastAPI, Header -from pydantic import BaseModel -from typing_extensions import Annotated - -app = FastAPI() - - -class CommonHeaders(BaseModel): - host: str - save_data: bool - if_modified_since: Union[str, None] = None - traceparent: Union[str, None] = None - x_tag: List[str] = [] - - -@app.get("/items/") -async def read_items( - headers: Annotated[CommonHeaders, Header(convert_underscores=False)], -): - return headers diff --git a/docs_src/header_params/tutorial001_an.py b/docs_src/header_params/tutorial001_an.py deleted file mode 100644 index 816c000862..0000000000 --- a/docs_src/header_params/tutorial001_an.py +++ /dev/null @@ -1,11 +0,0 @@ -from typing import Union - -from fastapi import FastAPI, Header -from typing_extensions import Annotated - -app = FastAPI() - - -@app.get("/items/") -async def read_items(user_agent: Annotated[Union[str, None], Header()] = None): - return {"User-Agent": user_agent} diff --git a/docs_src/header_params/tutorial001.py b/docs_src/header_params/tutorial001_py39.py similarity index 100% rename from docs_src/header_params/tutorial001.py rename to docs_src/header_params/tutorial001_py39.py diff --git a/docs_src/header_params/tutorial002_an.py b/docs_src/header_params/tutorial002_an.py deleted file mode 100644 index 82fe49ba2b..0000000000 --- a/docs_src/header_params/tutorial002_an.py +++ /dev/null @@ -1,15 +0,0 @@ -from typing import Union - -from fastapi import FastAPI, Header -from typing_extensions import Annotated - -app = FastAPI() - - -@app.get("/items/") -async def read_items( - strange_header: Annotated[ - Union[str, None], Header(convert_underscores=False) - ] = None, -): - return {"strange_header": strange_header} diff --git a/docs_src/header_params/tutorial002.py b/docs_src/header_params/tutorial002_py39.py similarity index 100% rename from docs_src/header_params/tutorial002.py rename to docs_src/header_params/tutorial002_py39.py diff --git a/docs_src/header_params/tutorial003.py b/docs_src/header_params/tutorial003.py deleted file mode 100644 index a61314aedb..0000000000 --- a/docs_src/header_params/tutorial003.py +++ /dev/null @@ -1,10 +0,0 @@ -from typing import List, Union - -from fastapi import FastAPI, Header - -app = FastAPI() - - -@app.get("/items/") -async def read_items(x_token: Union[List[str], None] = Header(default=None)): - return {"X-Token values": x_token} diff --git a/docs_src/header_params/tutorial003_an.py b/docs_src/header_params/tutorial003_an.py deleted file mode 100644 index 5406fd1f88..0000000000 --- a/docs_src/header_params/tutorial003_an.py +++ /dev/null @@ -1,11 +0,0 @@ -from typing import List, Union - -from fastapi import FastAPI, Header -from typing_extensions import Annotated - -app = FastAPI() - - -@app.get("/items/") -async def read_items(x_token: Annotated[Union[List[str], None], Header()] = None): - return {"X-Token values": x_token} diff --git a/docs_src/header_params/tutorial003_an_py39.py b/docs_src/header_params/tutorial003_an_py39.py index c1dd499611..5aad89407e 100644 --- a/docs_src/header_params/tutorial003_an_py39.py +++ b/docs_src/header_params/tutorial003_an_py39.py @@ -1,4 +1,4 @@ -from typing import Annotated, List, Union +from typing import Annotated, Union from fastapi import FastAPI, Header @@ -6,5 +6,5 @@ app = FastAPI() @app.get("/items/") -async def read_items(x_token: Annotated[Union[List[str], None], Header()] = None): +async def read_items(x_token: Annotated[Union[list[str], None], Header()] = None): return {"X-Token values": x_token} diff --git a/docs_src/metadata/tutorial001_1.py b/docs_src/metadata/tutorial001_1_py39.py similarity index 100% rename from docs_src/metadata/tutorial001_1.py rename to docs_src/metadata/tutorial001_1_py39.py diff --git a/docs_src/metadata/tutorial001.py b/docs_src/metadata/tutorial001_py39.py similarity index 100% rename from docs_src/metadata/tutorial001.py rename to docs_src/metadata/tutorial001_py39.py diff --git a/docs_src/metadata/tutorial002.py b/docs_src/metadata/tutorial002_py39.py similarity index 100% rename from docs_src/metadata/tutorial002.py rename to docs_src/metadata/tutorial002_py39.py diff --git a/docs_src/metadata/tutorial003.py b/docs_src/metadata/tutorial003_py39.py similarity index 100% rename from docs_src/metadata/tutorial003.py rename to docs_src/metadata/tutorial003_py39.py diff --git a/docs_src/metadata/tutorial004.py b/docs_src/metadata/tutorial004_py39.py similarity index 100% rename from docs_src/metadata/tutorial004.py rename to docs_src/metadata/tutorial004_py39.py diff --git a/docs_src/middleware/tutorial001.py b/docs_src/middleware/tutorial001_py39.py similarity index 100% rename from docs_src/middleware/tutorial001.py rename to docs_src/middleware/tutorial001_py39.py diff --git a/docs_src/openapi_callbacks/tutorial001.py b/docs_src/openapi_callbacks/tutorial001_py39.py similarity index 100% rename from docs_src/openapi_callbacks/tutorial001.py rename to docs_src/openapi_callbacks/tutorial001_py39.py diff --git a/docs_src/openapi_webhooks/tutorial001.py b/docs_src/openapi_webhooks/tutorial001_py39.py similarity index 100% rename from docs_src/openapi_webhooks/tutorial001.py rename to docs_src/openapi_webhooks/tutorial001_py39.py diff --git a/docs_src/path_operation_advanced_configuration/tutorial001.py b/docs_src/path_operation_advanced_configuration/tutorial001_py39.py similarity index 100% rename from docs_src/path_operation_advanced_configuration/tutorial001.py rename to docs_src/path_operation_advanced_configuration/tutorial001_py39.py diff --git a/docs_src/path_operation_advanced_configuration/tutorial002.py b/docs_src/path_operation_advanced_configuration/tutorial002_py39.py similarity index 100% rename from docs_src/path_operation_advanced_configuration/tutorial002.py rename to docs_src/path_operation_advanced_configuration/tutorial002_py39.py diff --git a/docs_src/path_operation_advanced_configuration/tutorial003.py b/docs_src/path_operation_advanced_configuration/tutorial003_py39.py similarity index 100% rename from docs_src/path_operation_advanced_configuration/tutorial003.py rename to docs_src/path_operation_advanced_configuration/tutorial003_py39.py diff --git a/docs_src/path_operation_advanced_configuration/tutorial004.py b/docs_src/path_operation_advanced_configuration/tutorial004.py deleted file mode 100644 index a3aad4ac40..0000000000 --- a/docs_src/path_operation_advanced_configuration/tutorial004.py +++ /dev/null @@ -1,30 +0,0 @@ -from typing import Set, Union - -from fastapi import FastAPI -from pydantic import BaseModel - -app = FastAPI() - - -class Item(BaseModel): - name: str - description: Union[str, None] = None - price: float - tax: Union[float, None] = None - tags: Set[str] = set() - - -@app.post("/items/", response_model=Item, summary="Create an item") -async def create_item(item: Item): - """ - Create an item with all the information: - - - **name**: each item must have a name - - **description**: a long description - - **price**: required - - **tax**: if the item doesn't have tax, you can omit this - - **tags**: a set of unique tag strings for this item - \f - :param item: User input. - """ - return item diff --git a/docs_src/path_operation_advanced_configuration/tutorial005.py b/docs_src/path_operation_advanced_configuration/tutorial005_py39.py similarity index 100% rename from docs_src/path_operation_advanced_configuration/tutorial005.py rename to docs_src/path_operation_advanced_configuration/tutorial005_py39.py diff --git a/docs_src/path_operation_advanced_configuration/tutorial006.py b/docs_src/path_operation_advanced_configuration/tutorial006_py39.py similarity index 100% rename from docs_src/path_operation_advanced_configuration/tutorial006.py rename to docs_src/path_operation_advanced_configuration/tutorial006_py39.py diff --git a/docs_src/path_operation_advanced_configuration/tutorial007.py b/docs_src/path_operation_advanced_configuration/tutorial007.py deleted file mode 100644 index 54e2e9399e..0000000000 --- a/docs_src/path_operation_advanced_configuration/tutorial007.py +++ /dev/null @@ -1,34 +0,0 @@ -from typing import List - -import yaml -from fastapi import FastAPI, HTTPException, Request -from pydantic import BaseModel, ValidationError - -app = FastAPI() - - -class Item(BaseModel): - name: str - tags: List[str] - - -@app.post( - "/items/", - openapi_extra={ - "requestBody": { - "content": {"application/x-yaml": {"schema": Item.model_json_schema()}}, - "required": True, - }, - }, -) -async def create_item(request: Request): - raw_body = await request.body() - try: - data = yaml.safe_load(raw_body) - except yaml.YAMLError: - raise HTTPException(status_code=422, detail="Invalid YAML") - try: - item = Item.model_validate(data) - except ValidationError as e: - raise HTTPException(status_code=422, detail=e.errors(include_url=False)) - return item diff --git a/docs_src/path_operation_advanced_configuration/tutorial007_pv1.py b/docs_src/path_operation_advanced_configuration/tutorial007_pv1.py deleted file mode 100644 index d51752bb87..0000000000 --- a/docs_src/path_operation_advanced_configuration/tutorial007_pv1.py +++ /dev/null @@ -1,34 +0,0 @@ -from typing import List - -import yaml -from fastapi import FastAPI, HTTPException, Request -from pydantic import BaseModel, ValidationError - -app = FastAPI() - - -class Item(BaseModel): - name: str - tags: List[str] - - -@app.post( - "/items/", - openapi_extra={ - "requestBody": { - "content": {"application/x-yaml": {"schema": Item.schema()}}, - "required": True, - }, - }, -) -async def create_item(request: Request): - raw_body = await request.body() - try: - data = yaml.safe_load(raw_body) - except yaml.YAMLError: - raise HTTPException(status_code=422, detail="Invalid YAML") - try: - item = Item.parse_obj(data) - except ValidationError as e: - raise HTTPException(status_code=422, detail=e.errors()) - return item diff --git a/docs_src/path_operation_configuration/tutorial001.py b/docs_src/path_operation_configuration/tutorial001.py deleted file mode 100644 index 83fd8377ab..0000000000 --- a/docs_src/path_operation_configuration/tutorial001.py +++ /dev/null @@ -1,19 +0,0 @@ -from typing import Set, Union - -from fastapi import FastAPI, status -from pydantic import BaseModel - -app = FastAPI() - - -class Item(BaseModel): - name: str - description: Union[str, None] = None - price: float - tax: Union[float, None] = None - tags: Set[str] = set() - - -@app.post("/items/", response_model=Item, status_code=status.HTTP_201_CREATED) -async def create_item(item: Item): - return item diff --git a/docs_src/path_operation_configuration/tutorial002.py b/docs_src/path_operation_configuration/tutorial002.py deleted file mode 100644 index 798b0c2311..0000000000 --- a/docs_src/path_operation_configuration/tutorial002.py +++ /dev/null @@ -1,29 +0,0 @@ -from typing import Set, Union - -from fastapi import FastAPI -from pydantic import BaseModel - -app = FastAPI() - - -class Item(BaseModel): - name: str - description: Union[str, None] = None - price: float - tax: Union[float, None] = None - tags: Set[str] = set() - - -@app.post("/items/", response_model=Item, tags=["items"]) -async def create_item(item: Item): - return item - - -@app.get("/items/", tags=["items"]) -async def read_items(): - return [{"name": "Foo", "price": 42}] - - -@app.get("/users/", tags=["users"]) -async def read_users(): - return [{"username": "johndoe"}] diff --git a/docs_src/path_operation_configuration/tutorial002b.py b/docs_src/path_operation_configuration/tutorial002b_py39.py similarity index 100% rename from docs_src/path_operation_configuration/tutorial002b.py rename to docs_src/path_operation_configuration/tutorial002b_py39.py diff --git a/docs_src/path_operation_configuration/tutorial003.py b/docs_src/path_operation_configuration/tutorial003.py deleted file mode 100644 index 26bf7dabae..0000000000 --- a/docs_src/path_operation_configuration/tutorial003.py +++ /dev/null @@ -1,24 +0,0 @@ -from typing import Set, Union - -from fastapi import FastAPI -from pydantic import BaseModel - -app = FastAPI() - - -class Item(BaseModel): - name: str - description: Union[str, None] = None - price: float - tax: Union[float, None] = None - tags: Set[str] = set() - - -@app.post( - "/items/", - response_model=Item, - summary="Create an item", - description="Create an item with all the information, name, description, price, tax and a set of unique tags", -) -async def create_item(item: Item): - return item diff --git a/docs_src/path_operation_configuration/tutorial004.py b/docs_src/path_operation_configuration/tutorial004.py deleted file mode 100644 index 8f865c58a6..0000000000 --- a/docs_src/path_operation_configuration/tutorial004.py +++ /dev/null @@ -1,28 +0,0 @@ -from typing import Set, Union - -from fastapi import FastAPI -from pydantic import BaseModel - -app = FastAPI() - - -class Item(BaseModel): - name: str - description: Union[str, None] = None - price: float - tax: Union[float, None] = None - tags: Set[str] = set() - - -@app.post("/items/", response_model=Item, summary="Create an item") -async def create_item(item: Item): - """ - Create an item with all the information: - - - **name**: each item must have a name - - **description**: a long description - - **price**: required - - **tax**: if the item doesn't have tax, you can omit this - - **tags**: a set of unique tag strings for this item - """ - return item diff --git a/docs_src/path_operation_configuration/tutorial005.py b/docs_src/path_operation_configuration/tutorial005.py deleted file mode 100644 index 2c1be4a34b..0000000000 --- a/docs_src/path_operation_configuration/tutorial005.py +++ /dev/null @@ -1,33 +0,0 @@ -from typing import Set, Union - -from fastapi import FastAPI -from pydantic import BaseModel - -app = FastAPI() - - -class Item(BaseModel): - name: str - description: Union[str, None] = None - price: float - tax: Union[float, None] = None - tags: Set[str] = set() - - -@app.post( - "/items/", - response_model=Item, - summary="Create an item", - response_description="The created item", -) -async def create_item(item: Item): - """ - Create an item with all the information: - - - **name**: each item must have a name - - **description**: a long description - - **price**: required - - **tax**: if the item doesn't have tax, you can omit this - - **tags**: a set of unique tag strings for this item - """ - return item diff --git a/docs_src/path_operation_configuration/tutorial006.py b/docs_src/path_operation_configuration/tutorial006_py39.py similarity index 100% rename from docs_src/path_operation_configuration/tutorial006.py rename to docs_src/path_operation_configuration/tutorial006_py39.py diff --git a/docs_src/path_params/tutorial001.py b/docs_src/path_params/tutorial001_py39.py similarity index 100% rename from docs_src/path_params/tutorial001.py rename to docs_src/path_params/tutorial001_py39.py diff --git a/docs_src/path_params/tutorial002.py b/docs_src/path_params/tutorial002_py39.py similarity index 100% rename from docs_src/path_params/tutorial002.py rename to docs_src/path_params/tutorial002_py39.py diff --git a/docs_src/path_params/tutorial003.py b/docs_src/path_params/tutorial003_py39.py similarity index 100% rename from docs_src/path_params/tutorial003.py rename to docs_src/path_params/tutorial003_py39.py diff --git a/docs_src/path_params/tutorial003b.py b/docs_src/path_params/tutorial003b_py39.py similarity index 100% rename from docs_src/path_params/tutorial003b.py rename to docs_src/path_params/tutorial003b_py39.py diff --git a/docs_src/path_params/tutorial004.py b/docs_src/path_params/tutorial004_py39.py similarity index 100% rename from docs_src/path_params/tutorial004.py rename to docs_src/path_params/tutorial004_py39.py diff --git a/docs_src/path_params/tutorial005.py b/docs_src/path_params/tutorial005_py39.py similarity index 100% rename from docs_src/path_params/tutorial005.py rename to docs_src/path_params/tutorial005_py39.py diff --git a/docs_src/path_params_numeric_validations/tutorial001_an.py b/docs_src/path_params_numeric_validations/tutorial001_an.py deleted file mode 100644 index 621be7b045..0000000000 --- a/docs_src/path_params_numeric_validations/tutorial001_an.py +++ /dev/null @@ -1,17 +0,0 @@ -from typing import Union - -from fastapi import FastAPI, Path, Query -from typing_extensions import Annotated - -app = FastAPI() - - -@app.get("/items/{item_id}") -async def read_items( - item_id: Annotated[int, Path(title="The ID of the item to get")], - q: Annotated[Union[str, None], Query(alias="item-query")] = None, -): - results = {"item_id": item_id} - if q: - results.update({"q": q}) - return results diff --git a/docs_src/path_params_numeric_validations/tutorial001.py b/docs_src/path_params_numeric_validations/tutorial001_py39.py similarity index 100% rename from docs_src/path_params_numeric_validations/tutorial001.py rename to docs_src/path_params_numeric_validations/tutorial001_py39.py diff --git a/docs_src/path_params_numeric_validations/tutorial002_an.py b/docs_src/path_params_numeric_validations/tutorial002_an.py deleted file mode 100644 index 322f8cf0bb..0000000000 --- a/docs_src/path_params_numeric_validations/tutorial002_an.py +++ /dev/null @@ -1,14 +0,0 @@ -from fastapi import FastAPI, Path -from typing_extensions import Annotated - -app = FastAPI() - - -@app.get("/items/{item_id}") -async def read_items( - q: str, item_id: Annotated[int, Path(title="The ID of the item to get")] -): - results = {"item_id": item_id} - if q: - results.update({"q": q}) - return results diff --git a/docs_src/path_params_numeric_validations/tutorial002.py b/docs_src/path_params_numeric_validations/tutorial002_py39.py similarity index 100% rename from docs_src/path_params_numeric_validations/tutorial002.py rename to docs_src/path_params_numeric_validations/tutorial002_py39.py diff --git a/docs_src/path_params_numeric_validations/tutorial003_an.py b/docs_src/path_params_numeric_validations/tutorial003_an.py deleted file mode 100644 index d0fa8b3db9..0000000000 --- a/docs_src/path_params_numeric_validations/tutorial003_an.py +++ /dev/null @@ -1,14 +0,0 @@ -from fastapi import FastAPI, Path -from typing_extensions import Annotated - -app = FastAPI() - - -@app.get("/items/{item_id}") -async def read_items( - item_id: Annotated[int, Path(title="The ID of the item to get")], q: str -): - results = {"item_id": item_id} - if q: - results.update({"q": q}) - return results diff --git a/docs_src/path_params_numeric_validations/tutorial003.py b/docs_src/path_params_numeric_validations/tutorial003_py39.py similarity index 100% rename from docs_src/path_params_numeric_validations/tutorial003.py rename to docs_src/path_params_numeric_validations/tutorial003_py39.py diff --git a/docs_src/path_params_numeric_validations/tutorial004_an.py b/docs_src/path_params_numeric_validations/tutorial004_an.py deleted file mode 100644 index ffc50f6c5b..0000000000 --- a/docs_src/path_params_numeric_validations/tutorial004_an.py +++ /dev/null @@ -1,14 +0,0 @@ -from fastapi import FastAPI, Path -from typing_extensions import Annotated - -app = FastAPI() - - -@app.get("/items/{item_id}") -async def read_items( - item_id: Annotated[int, Path(title="The ID of the item to get", ge=1)], q: str -): - results = {"item_id": item_id} - if q: - results.update({"q": q}) - return results diff --git a/docs_src/path_params_numeric_validations/tutorial004.py b/docs_src/path_params_numeric_validations/tutorial004_py39.py similarity index 100% rename from docs_src/path_params_numeric_validations/tutorial004.py rename to docs_src/path_params_numeric_validations/tutorial004_py39.py diff --git a/docs_src/path_params_numeric_validations/tutorial005_an.py b/docs_src/path_params_numeric_validations/tutorial005_an.py deleted file mode 100644 index 433c69129f..0000000000 --- a/docs_src/path_params_numeric_validations/tutorial005_an.py +++ /dev/null @@ -1,15 +0,0 @@ -from fastapi import FastAPI, Path -from typing_extensions import Annotated - -app = FastAPI() - - -@app.get("/items/{item_id}") -async def read_items( - item_id: Annotated[int, Path(title="The ID of the item to get", gt=0, le=1000)], - q: str, -): - results = {"item_id": item_id} - if q: - results.update({"q": q}) - return results diff --git a/docs_src/path_params_numeric_validations/tutorial005.py b/docs_src/path_params_numeric_validations/tutorial005_py39.py similarity index 100% rename from docs_src/path_params_numeric_validations/tutorial005.py rename to docs_src/path_params_numeric_validations/tutorial005_py39.py diff --git a/docs_src/path_params_numeric_validations/tutorial006_an.py b/docs_src/path_params_numeric_validations/tutorial006_an.py deleted file mode 100644 index ac47325732..0000000000 --- a/docs_src/path_params_numeric_validations/tutorial006_an.py +++ /dev/null @@ -1,19 +0,0 @@ -from fastapi import FastAPI, Path, Query -from typing_extensions import Annotated - -app = FastAPI() - - -@app.get("/items/{item_id}") -async def read_items( - *, - item_id: Annotated[int, Path(title="The ID of the item to get", ge=0, le=1000)], - q: str, - size: Annotated[float, Query(gt=0, lt=10.5)], -): - results = {"item_id": item_id} - if q: - results.update({"q": q}) - if size: - results.update({"size": size}) - return results diff --git a/docs_src/path_params_numeric_validations/tutorial006.py b/docs_src/path_params_numeric_validations/tutorial006_py39.py similarity index 100% rename from docs_src/path_params_numeric_validations/tutorial006.py rename to docs_src/path_params_numeric_validations/tutorial006_py39.py diff --git a/docs_src/pydantic_v1_in_v2/tutorial001_an.py b/docs_src/pydantic_v1_in_v2/tutorial001_an_py39.py similarity index 100% rename from docs_src/pydantic_v1_in_v2/tutorial001_an.py rename to docs_src/pydantic_v1_in_v2/tutorial001_an_py39.py diff --git a/docs_src/pydantic_v1_in_v2/tutorial002_an.py b/docs_src/pydantic_v1_in_v2/tutorial002_an_py39.py similarity index 100% rename from docs_src/pydantic_v1_in_v2/tutorial002_an.py rename to docs_src/pydantic_v1_in_v2/tutorial002_an_py39.py diff --git a/docs_src/pydantic_v1_in_v2/tutorial003_an.py b/docs_src/pydantic_v1_in_v2/tutorial003_an_py39.py similarity index 100% rename from docs_src/pydantic_v1_in_v2/tutorial003_an.py rename to docs_src/pydantic_v1_in_v2/tutorial003_an_py39.py diff --git a/docs_src/pydantic_v1_in_v2/tutorial004_an.py b/docs_src/pydantic_v1_in_v2/tutorial004_an.py deleted file mode 100644 index cca8a9ea80..0000000000 --- a/docs_src/pydantic_v1_in_v2/tutorial004_an.py +++ /dev/null @@ -1,20 +0,0 @@ -from typing import Union - -from fastapi import FastAPI -from fastapi.temp_pydantic_v1_params import Body -from pydantic.v1 import BaseModel -from typing_extensions import Annotated - - -class Item(BaseModel): - name: str - description: Union[str, None] = None - size: float - - -app = FastAPI() - - -@app.post("/items/") -async def create_item(item: Annotated[Item, Body(embed=True)]) -> Item: - return item diff --git a/docs_src/python_types/tutorial001.py b/docs_src/python_types/tutorial001_py39.py similarity index 100% rename from docs_src/python_types/tutorial001.py rename to docs_src/python_types/tutorial001_py39.py diff --git a/docs_src/python_types/tutorial002.py b/docs_src/python_types/tutorial002_py39.py similarity index 100% rename from docs_src/python_types/tutorial002.py rename to docs_src/python_types/tutorial002_py39.py diff --git a/docs_src/python_types/tutorial003.py b/docs_src/python_types/tutorial003_py39.py similarity index 100% rename from docs_src/python_types/tutorial003.py rename to docs_src/python_types/tutorial003_py39.py diff --git a/docs_src/python_types/tutorial004.py b/docs_src/python_types/tutorial004_py39.py similarity index 100% rename from docs_src/python_types/tutorial004.py rename to docs_src/python_types/tutorial004_py39.py diff --git a/docs_src/python_types/tutorial005.py b/docs_src/python_types/tutorial005_py39.py similarity index 100% rename from docs_src/python_types/tutorial005.py rename to docs_src/python_types/tutorial005_py39.py diff --git a/docs_src/python_types/tutorial006.py b/docs_src/python_types/tutorial006.py deleted file mode 100644 index 87394ecb0c..0000000000 --- a/docs_src/python_types/tutorial006.py +++ /dev/null @@ -1,6 +0,0 @@ -from typing import List - - -def process_items(items: List[str]): - for item in items: - print(item) diff --git a/docs_src/python_types/tutorial007.py b/docs_src/python_types/tutorial007.py deleted file mode 100644 index 5b13f15494..0000000000 --- a/docs_src/python_types/tutorial007.py +++ /dev/null @@ -1,5 +0,0 @@ -from typing import Set, Tuple - - -def process_items(items_t: Tuple[int, int, str], items_s: Set[bytes]): - return items_t, items_s diff --git a/docs_src/python_types/tutorial008.py b/docs_src/python_types/tutorial008.py deleted file mode 100644 index 9fb1043bb8..0000000000 --- a/docs_src/python_types/tutorial008.py +++ /dev/null @@ -1,7 +0,0 @@ -from typing import Dict - - -def process_items(prices: Dict[str, float]): - for item_name, item_price in prices.items(): - print(item_name) - print(item_price) diff --git a/docs_src/python_types/tutorial008b.py b/docs_src/python_types/tutorial008b_py39.py similarity index 100% rename from docs_src/python_types/tutorial008b.py rename to docs_src/python_types/tutorial008b_py39.py diff --git a/docs_src/python_types/tutorial009.py b/docs_src/python_types/tutorial009_py39.py similarity index 100% rename from docs_src/python_types/tutorial009.py rename to docs_src/python_types/tutorial009_py39.py diff --git a/docs_src/python_types/tutorial009b.py b/docs_src/python_types/tutorial009b_py39.py similarity index 100% rename from docs_src/python_types/tutorial009b.py rename to docs_src/python_types/tutorial009b_py39.py diff --git a/docs_src/python_types/tutorial009c.py b/docs_src/python_types/tutorial009c_py39.py similarity index 100% rename from docs_src/python_types/tutorial009c.py rename to docs_src/python_types/tutorial009c_py39.py diff --git a/docs_src/python_types/tutorial010.py b/docs_src/python_types/tutorial010_py39.py similarity index 100% rename from docs_src/python_types/tutorial010.py rename to docs_src/python_types/tutorial010_py39.py diff --git a/docs_src/python_types/tutorial011.py b/docs_src/python_types/tutorial011.py deleted file mode 100644 index 297a84db68..0000000000 --- a/docs_src/python_types/tutorial011.py +++ /dev/null @@ -1,23 +0,0 @@ -from datetime import datetime -from typing import List, Union - -from pydantic import BaseModel - - -class User(BaseModel): - id: int - name: str = "John Doe" - signup_ts: Union[datetime, None] = None - friends: List[int] = [] - - -external_data = { - "id": "123", - "signup_ts": "2017-06-01 12:22", - "friends": [1, "2", b"3"], -} -user = User(**external_data) -print(user) -# > User id=123 name='John Doe' signup_ts=datetime.datetime(2017, 6, 1, 12, 22) friends=[1, 2, 3] -print(user.id) -# > 123 diff --git a/docs_src/python_types/tutorial012.py b/docs_src/python_types/tutorial012_py39.py similarity index 100% rename from docs_src/python_types/tutorial012.py rename to docs_src/python_types/tutorial012_py39.py diff --git a/docs_src/python_types/tutorial013.py b/docs_src/python_types/tutorial013.py deleted file mode 100644 index 0ec7735199..0000000000 --- a/docs_src/python_types/tutorial013.py +++ /dev/null @@ -1,5 +0,0 @@ -from typing_extensions import Annotated - - -def say_hello(name: Annotated[str, "this is just metadata"]) -> str: - return f"Hello {name}" diff --git a/docs_src/query_param_models/tutorial001.py b/docs_src/query_param_models/tutorial001.py deleted file mode 100644 index 0c0ab315e8..0000000000 --- a/docs_src/query_param_models/tutorial001.py +++ /dev/null @@ -1,19 +0,0 @@ -from typing import List - -from fastapi import FastAPI, Query -from pydantic import BaseModel, Field -from typing_extensions import Literal - -app = FastAPI() - - -class FilterParams(BaseModel): - limit: int = Field(100, gt=0, le=100) - offset: int = Field(0, ge=0) - order_by: Literal["created_at", "updated_at"] = "created_at" - tags: List[str] = [] - - -@app.get("/items/") -async def read_items(filter_query: FilterParams = Query()): - return filter_query diff --git a/docs_src/query_param_models/tutorial001_an.py b/docs_src/query_param_models/tutorial001_an.py deleted file mode 100644 index 28375057c1..0000000000 --- a/docs_src/query_param_models/tutorial001_an.py +++ /dev/null @@ -1,19 +0,0 @@ -from typing import List - -from fastapi import FastAPI, Query -from pydantic import BaseModel, Field -from typing_extensions import Annotated, Literal - -app = FastAPI() - - -class FilterParams(BaseModel): - limit: int = Field(100, gt=0, le=100) - offset: int = Field(0, ge=0) - order_by: Literal["created_at", "updated_at"] = "created_at" - tags: List[str] = [] - - -@app.get("/items/") -async def read_items(filter_query: Annotated[FilterParams, Query()]): - return filter_query diff --git a/docs_src/query_param_models/tutorial001_an_py39.py b/docs_src/query_param_models/tutorial001_an_py39.py index ba690d3e3f..71427acae1 100644 --- a/docs_src/query_param_models/tutorial001_an_py39.py +++ b/docs_src/query_param_models/tutorial001_an_py39.py @@ -1,6 +1,7 @@ +from typing import Annotated, Literal + from fastapi import FastAPI, Query from pydantic import BaseModel, Field -from typing_extensions import Annotated, Literal app = FastAPI() diff --git a/docs_src/query_param_models/tutorial001_py39.py b/docs_src/query_param_models/tutorial001_py39.py index 54b52a054c..3ebf9f4d70 100644 --- a/docs_src/query_param_models/tutorial001_py39.py +++ b/docs_src/query_param_models/tutorial001_py39.py @@ -1,6 +1,7 @@ +from typing import Literal + from fastapi import FastAPI, Query from pydantic import BaseModel, Field -from typing_extensions import Literal app = FastAPI() diff --git a/docs_src/query_param_models/tutorial002.py b/docs_src/query_param_models/tutorial002.py deleted file mode 100644 index 1633bc4644..0000000000 --- a/docs_src/query_param_models/tutorial002.py +++ /dev/null @@ -1,21 +0,0 @@ -from typing import List - -from fastapi import FastAPI, Query -from pydantic import BaseModel, Field -from typing_extensions import Literal - -app = FastAPI() - - -class FilterParams(BaseModel): - model_config = {"extra": "forbid"} - - limit: int = Field(100, gt=0, le=100) - offset: int = Field(0, ge=0) - order_by: Literal["created_at", "updated_at"] = "created_at" - tags: List[str] = [] - - -@app.get("/items/") -async def read_items(filter_query: FilterParams = Query()): - return filter_query diff --git a/docs_src/query_param_models/tutorial002_an.py b/docs_src/query_param_models/tutorial002_an.py deleted file mode 100644 index 69705d4b4b..0000000000 --- a/docs_src/query_param_models/tutorial002_an.py +++ /dev/null @@ -1,21 +0,0 @@ -from typing import List - -from fastapi import FastAPI, Query -from pydantic import BaseModel, Field -from typing_extensions import Annotated, Literal - -app = FastAPI() - - -class FilterParams(BaseModel): - model_config = {"extra": "forbid"} - - limit: int = Field(100, gt=0, le=100) - offset: int = Field(0, ge=0) - order_by: Literal["created_at", "updated_at"] = "created_at" - tags: List[str] = [] - - -@app.get("/items/") -async def read_items(filter_query: Annotated[FilterParams, Query()]): - return filter_query diff --git a/docs_src/query_param_models/tutorial002_an_py39.py b/docs_src/query_param_models/tutorial002_an_py39.py index 2d4c1a62b5..9759565023 100644 --- a/docs_src/query_param_models/tutorial002_an_py39.py +++ b/docs_src/query_param_models/tutorial002_an_py39.py @@ -1,6 +1,7 @@ +from typing import Annotated, Literal + from fastapi import FastAPI, Query from pydantic import BaseModel, Field -from typing_extensions import Annotated, Literal app = FastAPI() diff --git a/docs_src/query_param_models/tutorial002_pv1.py b/docs_src/query_param_models/tutorial002_pv1.py deleted file mode 100644 index 71ccd961d3..0000000000 --- a/docs_src/query_param_models/tutorial002_pv1.py +++ /dev/null @@ -1,22 +0,0 @@ -from typing import List - -from fastapi import FastAPI, Query -from pydantic import BaseModel, Field -from typing_extensions import Literal - -app = FastAPI() - - -class FilterParams(BaseModel): - class Config: - extra = "forbid" - - limit: int = Field(100, gt=0, le=100) - offset: int = Field(0, ge=0) - order_by: Literal["created_at", "updated_at"] = "created_at" - tags: List[str] = [] - - -@app.get("/items/") -async def read_items(filter_query: FilterParams = Query()): - return filter_query diff --git a/docs_src/query_param_models/tutorial002_pv1_an.py b/docs_src/query_param_models/tutorial002_pv1_an.py deleted file mode 100644 index 1dd29157a4..0000000000 --- a/docs_src/query_param_models/tutorial002_pv1_an.py +++ /dev/null @@ -1,22 +0,0 @@ -from typing import List - -from fastapi import FastAPI, Query -from pydantic import BaseModel, Field -from typing_extensions import Annotated, Literal - -app = FastAPI() - - -class FilterParams(BaseModel): - class Config: - extra = "forbid" - - limit: int = Field(100, gt=0, le=100) - offset: int = Field(0, ge=0) - order_by: Literal["created_at", "updated_at"] = "created_at" - tags: List[str] = [] - - -@app.get("/items/") -async def read_items(filter_query: Annotated[FilterParams, Query()]): - return filter_query diff --git a/docs_src/query_param_models/tutorial002_pv1_an_py39.py b/docs_src/query_param_models/tutorial002_pv1_an_py39.py index 494fef11fc..d635aae88f 100644 --- a/docs_src/query_param_models/tutorial002_pv1_an_py39.py +++ b/docs_src/query_param_models/tutorial002_pv1_an_py39.py @@ -1,6 +1,7 @@ +from typing import Annotated, Literal + from fastapi import FastAPI, Query from pydantic import BaseModel, Field -from typing_extensions import Annotated, Literal app = FastAPI() diff --git a/docs_src/query_param_models/tutorial002_pv1_py39.py b/docs_src/query_param_models/tutorial002_pv1_py39.py index 7fa456a791..9ffdeefc06 100644 --- a/docs_src/query_param_models/tutorial002_pv1_py39.py +++ b/docs_src/query_param_models/tutorial002_pv1_py39.py @@ -1,6 +1,7 @@ +from typing import Literal + from fastapi import FastAPI, Query from pydantic import BaseModel, Field -from typing_extensions import Literal app = FastAPI() diff --git a/docs_src/query_param_models/tutorial002_py39.py b/docs_src/query_param_models/tutorial002_py39.py index f9bba028c2..6ec4184991 100644 --- a/docs_src/query_param_models/tutorial002_py39.py +++ b/docs_src/query_param_models/tutorial002_py39.py @@ -1,6 +1,7 @@ +from typing import Literal + from fastapi import FastAPI, Query from pydantic import BaseModel, Field -from typing_extensions import Literal app = FastAPI() diff --git a/docs_src/query_params/tutorial001.py b/docs_src/query_params/tutorial001_py39.py similarity index 100% rename from docs_src/query_params/tutorial001.py rename to docs_src/query_params/tutorial001_py39.py diff --git a/docs_src/query_params/tutorial002.py b/docs_src/query_params/tutorial002_py39.py similarity index 100% rename from docs_src/query_params/tutorial002.py rename to docs_src/query_params/tutorial002_py39.py diff --git a/docs_src/query_params/tutorial003.py b/docs_src/query_params/tutorial003_py39.py similarity index 100% rename from docs_src/query_params/tutorial003.py rename to docs_src/query_params/tutorial003_py39.py diff --git a/docs_src/query_params/tutorial004.py b/docs_src/query_params/tutorial004_py39.py similarity index 100% rename from docs_src/query_params/tutorial004.py rename to docs_src/query_params/tutorial004_py39.py diff --git a/docs_src/query_params/tutorial005.py b/docs_src/query_params/tutorial005_py39.py similarity index 100% rename from docs_src/query_params/tutorial005.py rename to docs_src/query_params/tutorial005_py39.py diff --git a/docs_src/query_params/tutorial006.py b/docs_src/query_params/tutorial006_py39.py similarity index 100% rename from docs_src/query_params/tutorial006.py rename to docs_src/query_params/tutorial006_py39.py diff --git a/docs_src/query_params/tutorial006b.py b/docs_src/query_params/tutorial006b.py deleted file mode 100644 index f0dbfe08fe..0000000000 --- a/docs_src/query_params/tutorial006b.py +++ /dev/null @@ -1,13 +0,0 @@ -from typing import Union - -from fastapi import FastAPI - -app = FastAPI() - - -@app.get("/items/{item_id}") -async def read_user_item( - item_id: str, needy: str, skip: int = 0, limit: Union[int, None] = None -): - item = {"item_id": item_id, "needy": needy, "skip": skip, "limit": limit} - return item diff --git a/docs_src/query_params_str_validations/tutorial001.py b/docs_src/query_params_str_validations/tutorial001_py39.py similarity index 100% rename from docs_src/query_params_str_validations/tutorial001.py rename to docs_src/query_params_str_validations/tutorial001_py39.py diff --git a/docs_src/query_params_str_validations/tutorial002_an.py b/docs_src/query_params_str_validations/tutorial002_an_py39.py similarity index 81% rename from docs_src/query_params_str_validations/tutorial002_an.py rename to docs_src/query_params_str_validations/tutorial002_an_py39.py index cb1b38940c..2d8fc97985 100644 --- a/docs_src/query_params_str_validations/tutorial002_an.py +++ b/docs_src/query_params_str_validations/tutorial002_an_py39.py @@ -1,7 +1,6 @@ -from typing import Union +from typing import Annotated, Union from fastapi import FastAPI, Query -from typing_extensions import Annotated app = FastAPI() diff --git a/docs_src/query_params_str_validations/tutorial002.py b/docs_src/query_params_str_validations/tutorial002_py39.py similarity index 100% rename from docs_src/query_params_str_validations/tutorial002.py rename to docs_src/query_params_str_validations/tutorial002_py39.py diff --git a/docs_src/query_params_str_validations/tutorial003_an.py b/docs_src/query_params_str_validations/tutorial003_an.py deleted file mode 100644 index 0dd14086cf..0000000000 --- a/docs_src/query_params_str_validations/tutorial003_an.py +++ /dev/null @@ -1,16 +0,0 @@ -from typing import Union - -from fastapi import FastAPI, Query -from typing_extensions import Annotated - -app = FastAPI() - - -@app.get("/items/") -async def read_items( - q: Annotated[Union[str, None], Query(min_length=3, max_length=50)] = None, -): - results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]} - if q: - results.update({"q": q}) - return results diff --git a/docs_src/query_params_str_validations/tutorial003.py b/docs_src/query_params_str_validations/tutorial003_py39.py similarity index 100% rename from docs_src/query_params_str_validations/tutorial003.py rename to docs_src/query_params_str_validations/tutorial003_py39.py diff --git a/docs_src/query_params_str_validations/tutorial004_an.py b/docs_src/query_params_str_validations/tutorial004_an.py deleted file mode 100644 index c75d45d63e..0000000000 --- a/docs_src/query_params_str_validations/tutorial004_an.py +++ /dev/null @@ -1,18 +0,0 @@ -from typing import Union - -from fastapi import FastAPI, Query -from typing_extensions import Annotated - -app = FastAPI() - - -@app.get("/items/") -async def read_items( - q: Annotated[ - Union[str, None], Query(min_length=3, max_length=50, pattern="^fixedquery$") - ] = None, -): - results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]} - if q: - results.update({"q": q}) - return results diff --git a/docs_src/query_params_str_validations/tutorial004.py b/docs_src/query_params_str_validations/tutorial004_py39.py similarity index 100% rename from docs_src/query_params_str_validations/tutorial004.py rename to docs_src/query_params_str_validations/tutorial004_py39.py diff --git a/docs_src/query_params_str_validations/tutorial005_an.py b/docs_src/query_params_str_validations/tutorial005_an.py deleted file mode 100644 index 452d4d38d7..0000000000 --- a/docs_src/query_params_str_validations/tutorial005_an.py +++ /dev/null @@ -1,12 +0,0 @@ -from fastapi import FastAPI, Query -from typing_extensions import Annotated - -app = FastAPI() - - -@app.get("/items/") -async def read_items(q: Annotated[str, Query(min_length=3)] = "fixedquery"): - results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]} - if q: - results.update({"q": q}) - return results diff --git a/docs_src/query_params_str_validations/tutorial005.py b/docs_src/query_params_str_validations/tutorial005_py39.py similarity index 100% rename from docs_src/query_params_str_validations/tutorial005.py rename to docs_src/query_params_str_validations/tutorial005_py39.py diff --git a/docs_src/query_params_str_validations/tutorial006_an.py b/docs_src/query_params_str_validations/tutorial006_an.py deleted file mode 100644 index 559480d2bf..0000000000 --- a/docs_src/query_params_str_validations/tutorial006_an.py +++ /dev/null @@ -1,12 +0,0 @@ -from fastapi import FastAPI, Query -from typing_extensions import Annotated - -app = FastAPI() - - -@app.get("/items/") -async def read_items(q: Annotated[str, Query(min_length=3)]): - results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]} - if q: - results.update({"q": q}) - return results diff --git a/docs_src/query_params_str_validations/tutorial006.py b/docs_src/query_params_str_validations/tutorial006_py39.py similarity index 100% rename from docs_src/query_params_str_validations/tutorial006.py rename to docs_src/query_params_str_validations/tutorial006_py39.py diff --git a/docs_src/query_params_str_validations/tutorial006c_an.py b/docs_src/query_params_str_validations/tutorial006c_an.py deleted file mode 100644 index 55c4f4adca..0000000000 --- a/docs_src/query_params_str_validations/tutorial006c_an.py +++ /dev/null @@ -1,14 +0,0 @@ -from typing import Union - -from fastapi import FastAPI, Query -from typing_extensions import Annotated - -app = FastAPI() - - -@app.get("/items/") -async def read_items(q: Annotated[Union[str, None], Query(min_length=3)]): - results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]} - if q: - results.update({"q": q}) - return results diff --git a/docs_src/query_params_str_validations/tutorial006c.py b/docs_src/query_params_str_validations/tutorial006c_py39.py similarity index 100% rename from docs_src/query_params_str_validations/tutorial006c.py rename to docs_src/query_params_str_validations/tutorial006c_py39.py diff --git a/docs_src/query_params_str_validations/tutorial007_an.py b/docs_src/query_params_str_validations/tutorial007_an.py deleted file mode 100644 index 4b3c8de4b9..0000000000 --- a/docs_src/query_params_str_validations/tutorial007_an.py +++ /dev/null @@ -1,16 +0,0 @@ -from typing import Union - -from fastapi import FastAPI, Query -from typing_extensions import Annotated - -app = FastAPI() - - -@app.get("/items/") -async def read_items( - q: Annotated[Union[str, None], Query(title="Query string", min_length=3)] = None, -): - results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]} - if q: - results.update({"q": q}) - return results diff --git a/docs_src/query_params_str_validations/tutorial007.py b/docs_src/query_params_str_validations/tutorial007_py39.py similarity index 100% rename from docs_src/query_params_str_validations/tutorial007.py rename to docs_src/query_params_str_validations/tutorial007_py39.py diff --git a/docs_src/query_params_str_validations/tutorial008_an.py b/docs_src/query_params_str_validations/tutorial008_an.py deleted file mode 100644 index 01606a9203..0000000000 --- a/docs_src/query_params_str_validations/tutorial008_an.py +++ /dev/null @@ -1,23 +0,0 @@ -from typing import Union - -from fastapi import FastAPI, Query -from typing_extensions import Annotated - -app = FastAPI() - - -@app.get("/items/") -async def read_items( - q: Annotated[ - Union[str, None], - Query( - title="Query string", - description="Query string for the items to search in the database that have a good match", - min_length=3, - ), - ] = None, -): - results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]} - if q: - results.update({"q": q}) - return results diff --git a/docs_src/query_params_str_validations/tutorial008.py b/docs_src/query_params_str_validations/tutorial008_py39.py similarity index 100% rename from docs_src/query_params_str_validations/tutorial008.py rename to docs_src/query_params_str_validations/tutorial008_py39.py diff --git a/docs_src/query_params_str_validations/tutorial009_an.py b/docs_src/query_params_str_validations/tutorial009_an.py deleted file mode 100644 index 2894e2d51a..0000000000 --- a/docs_src/query_params_str_validations/tutorial009_an.py +++ /dev/null @@ -1,14 +0,0 @@ -from typing import Union - -from fastapi import FastAPI, Query -from typing_extensions import Annotated - -app = FastAPI() - - -@app.get("/items/") -async def read_items(q: Annotated[Union[str, None], Query(alias="item-query")] = None): - results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]} - if q: - results.update({"q": q}) - return results diff --git a/docs_src/query_params_str_validations/tutorial009.py b/docs_src/query_params_str_validations/tutorial009_py39.py similarity index 100% rename from docs_src/query_params_str_validations/tutorial009.py rename to docs_src/query_params_str_validations/tutorial009_py39.py diff --git a/docs_src/query_params_str_validations/tutorial010_an.py b/docs_src/query_params_str_validations/tutorial010_an.py deleted file mode 100644 index ed343230f4..0000000000 --- a/docs_src/query_params_str_validations/tutorial010_an.py +++ /dev/null @@ -1,27 +0,0 @@ -from typing import Union - -from fastapi import FastAPI, Query -from typing_extensions import Annotated - -app = FastAPI() - - -@app.get("/items/") -async def read_items( - q: Annotated[ - Union[str, None], - Query( - alias="item-query", - title="Query string", - description="Query string for the items to search in the database that have a good match", - min_length=3, - max_length=50, - pattern="^fixedquery$", - deprecated=True, - ), - ] = None, -): - results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]} - if q: - results.update({"q": q}) - return results diff --git a/docs_src/query_params_str_validations/tutorial010.py b/docs_src/query_params_str_validations/tutorial010_py39.py similarity index 100% rename from docs_src/query_params_str_validations/tutorial010.py rename to docs_src/query_params_str_validations/tutorial010_py39.py diff --git a/docs_src/query_params_str_validations/tutorial011.py b/docs_src/query_params_str_validations/tutorial011.py deleted file mode 100644 index 65bbce781a..0000000000 --- a/docs_src/query_params_str_validations/tutorial011.py +++ /dev/null @@ -1,11 +0,0 @@ -from typing import List, Union - -from fastapi import FastAPI, Query - -app = FastAPI() - - -@app.get("/items/") -async def read_items(q: Union[List[str], None] = Query(default=None)): - query_items = {"q": q} - return query_items diff --git a/docs_src/query_params_str_validations/tutorial011_an.py b/docs_src/query_params_str_validations/tutorial011_an.py deleted file mode 100644 index 8ed699337d..0000000000 --- a/docs_src/query_params_str_validations/tutorial011_an.py +++ /dev/null @@ -1,12 +0,0 @@ -from typing import List, Union - -from fastapi import FastAPI, Query -from typing_extensions import Annotated - -app = FastAPI() - - -@app.get("/items/") -async def read_items(q: Annotated[Union[List[str], None], Query()] = None): - query_items = {"q": q} - return query_items diff --git a/docs_src/query_params_str_validations/tutorial012.py b/docs_src/query_params_str_validations/tutorial012.py deleted file mode 100644 index e77d56974d..0000000000 --- a/docs_src/query_params_str_validations/tutorial012.py +++ /dev/null @@ -1,11 +0,0 @@ -from typing import List - -from fastapi import FastAPI, Query - -app = FastAPI() - - -@app.get("/items/") -async def read_items(q: List[str] = Query(default=["foo", "bar"])): - query_items = {"q": q} - return query_items diff --git a/docs_src/query_params_str_validations/tutorial012_an.py b/docs_src/query_params_str_validations/tutorial012_an.py deleted file mode 100644 index 261af250a1..0000000000 --- a/docs_src/query_params_str_validations/tutorial012_an.py +++ /dev/null @@ -1,12 +0,0 @@ -from typing import List - -from fastapi import FastAPI, Query -from typing_extensions import Annotated - -app = FastAPI() - - -@app.get("/items/") -async def read_items(q: Annotated[List[str], Query()] = ["foo", "bar"]): - query_items = {"q": q} - return query_items diff --git a/docs_src/query_params_str_validations/tutorial013_an.py b/docs_src/query_params_str_validations/tutorial013_an.py deleted file mode 100644 index f12a250559..0000000000 --- a/docs_src/query_params_str_validations/tutorial013_an.py +++ /dev/null @@ -1,10 +0,0 @@ -from fastapi import FastAPI, Query -from typing_extensions import Annotated - -app = FastAPI() - - -@app.get("/items/") -async def read_items(q: Annotated[list, Query()] = []): - query_items = {"q": q} - return query_items diff --git a/docs_src/query_params_str_validations/tutorial013.py b/docs_src/query_params_str_validations/tutorial013_py39.py similarity index 100% rename from docs_src/query_params_str_validations/tutorial013.py rename to docs_src/query_params_str_validations/tutorial013_py39.py diff --git a/docs_src/query_params_str_validations/tutorial014_an.py b/docs_src/query_params_str_validations/tutorial014_an.py deleted file mode 100644 index 2eaa585407..0000000000 --- a/docs_src/query_params_str_validations/tutorial014_an.py +++ /dev/null @@ -1,16 +0,0 @@ -from typing import Union - -from fastapi import FastAPI, Query -from typing_extensions import Annotated - -app = FastAPI() - - -@app.get("/items/") -async def read_items( - hidden_query: Annotated[Union[str, None], Query(include_in_schema=False)] = None, -): - if hidden_query: - return {"hidden_query": hidden_query} - else: - return {"hidden_query": "Not found"} diff --git a/docs_src/query_params_str_validations/tutorial014.py b/docs_src/query_params_str_validations/tutorial014_py39.py similarity index 100% rename from docs_src/query_params_str_validations/tutorial014.py rename to docs_src/query_params_str_validations/tutorial014_py39.py diff --git a/docs_src/query_params_str_validations/tutorial015_an.py b/docs_src/query_params_str_validations/tutorial015_an.py deleted file mode 100644 index f2ec6db123..0000000000 --- a/docs_src/query_params_str_validations/tutorial015_an.py +++ /dev/null @@ -1,31 +0,0 @@ -import random -from typing import Union - -from fastapi import FastAPI -from pydantic import AfterValidator -from typing_extensions import Annotated - -app = FastAPI() - -data = { - "isbn-9781529046137": "The Hitchhiker's Guide to the Galaxy", - "imdb-tt0371724": "The Hitchhiker's Guide to the Galaxy", - "isbn-9781439512982": "Isaac Asimov: The Complete Stories, Vol. 2", -} - - -def check_valid_id(id: str): - if not id.startswith(("isbn-", "imdb-")): - raise ValueError('Invalid ID format, it must start with "isbn-" or "imdb-"') - return id - - -@app.get("/items/") -async def read_items( - id: Annotated[Union[str, None], AfterValidator(check_valid_id)] = None, -): - if id: - item = data.get(id) - else: - id, item = random.choice(list(data.items())) - return {"id": id, "name": item} diff --git a/docs_src/request_files/tutorial001_02_an.py b/docs_src/request_files/tutorial001_02_an.py deleted file mode 100644 index 5007fef159..0000000000 --- a/docs_src/request_files/tutorial001_02_an.py +++ /dev/null @@ -1,22 +0,0 @@ -from typing import Union - -from fastapi import FastAPI, File, UploadFile -from typing_extensions import Annotated - -app = FastAPI() - - -@app.post("/files/") -async def create_file(file: Annotated[Union[bytes, None], File()] = None): - if not file: - return {"message": "No file sent"} - else: - return {"file_size": len(file)} - - -@app.post("/uploadfile/") -async def create_upload_file(file: Union[UploadFile, None] = None): - if not file: - return {"message": "No upload file sent"} - else: - return {"filename": file.filename} diff --git a/docs_src/request_files/tutorial001_02.py b/docs_src/request_files/tutorial001_02_py39.py similarity index 100% rename from docs_src/request_files/tutorial001_02.py rename to docs_src/request_files/tutorial001_02_py39.py diff --git a/docs_src/request_files/tutorial001_03_an.py b/docs_src/request_files/tutorial001_03_an.py deleted file mode 100644 index 8a6b0a2455..0000000000 --- a/docs_src/request_files/tutorial001_03_an.py +++ /dev/null @@ -1,16 +0,0 @@ -from fastapi import FastAPI, File, UploadFile -from typing_extensions import Annotated - -app = FastAPI() - - -@app.post("/files/") -async def create_file(file: Annotated[bytes, File(description="A file read as bytes")]): - return {"file_size": len(file)} - - -@app.post("/uploadfile/") -async def create_upload_file( - file: Annotated[UploadFile, File(description="A file read as UploadFile")], -): - return {"filename": file.filename} diff --git a/docs_src/request_files/tutorial001_03.py b/docs_src/request_files/tutorial001_03_py39.py similarity index 100% rename from docs_src/request_files/tutorial001_03.py rename to docs_src/request_files/tutorial001_03_py39.py diff --git a/docs_src/request_files/tutorial001_an.py b/docs_src/request_files/tutorial001_an.py deleted file mode 100644 index ca2f76d5c6..0000000000 --- a/docs_src/request_files/tutorial001_an.py +++ /dev/null @@ -1,14 +0,0 @@ -from fastapi import FastAPI, File, UploadFile -from typing_extensions import Annotated - -app = FastAPI() - - -@app.post("/files/") -async def create_file(file: Annotated[bytes, File()]): - return {"file_size": len(file)} - - -@app.post("/uploadfile/") -async def create_upload_file(file: UploadFile): - return {"filename": file.filename} diff --git a/docs_src/request_files/tutorial001.py b/docs_src/request_files/tutorial001_py39.py similarity index 100% rename from docs_src/request_files/tutorial001.py rename to docs_src/request_files/tutorial001_py39.py diff --git a/docs_src/request_files/tutorial002.py b/docs_src/request_files/tutorial002.py deleted file mode 100644 index b4d0acc68f..0000000000 --- a/docs_src/request_files/tutorial002.py +++ /dev/null @@ -1,33 +0,0 @@ -from typing import List - -from fastapi import FastAPI, File, UploadFile -from fastapi.responses import HTMLResponse - -app = FastAPI() - - -@app.post("/files/") -async def create_files(files: List[bytes] = File()): - return {"file_sizes": [len(file) for file in files]} - - -@app.post("/uploadfiles/") -async def create_upload_files(files: List[UploadFile]): - return {"filenames": [file.filename for file in files]} - - -@app.get("/") -async def main(): - content = """ - -
- - -
-
- - -
- - """ - return HTMLResponse(content=content) diff --git a/docs_src/request_files/tutorial002_an.py b/docs_src/request_files/tutorial002_an.py deleted file mode 100644 index eaa90da2b6..0000000000 --- a/docs_src/request_files/tutorial002_an.py +++ /dev/null @@ -1,34 +0,0 @@ -from typing import List - -from fastapi import FastAPI, File, UploadFile -from fastapi.responses import HTMLResponse -from typing_extensions import Annotated - -app = FastAPI() - - -@app.post("/files/") -async def create_files(files: Annotated[List[bytes], File()]): - return {"file_sizes": [len(file) for file in files]} - - -@app.post("/uploadfiles/") -async def create_upload_files(files: List[UploadFile]): - return {"filenames": [file.filename for file in files]} - - -@app.get("/") -async def main(): - content = """ - -
- - -
-
- - -
- - """ - return HTMLResponse(content=content) diff --git a/docs_src/request_files/tutorial003.py b/docs_src/request_files/tutorial003.py deleted file mode 100644 index e3f805f605..0000000000 --- a/docs_src/request_files/tutorial003.py +++ /dev/null @@ -1,37 +0,0 @@ -from typing import List - -from fastapi import FastAPI, File, UploadFile -from fastapi.responses import HTMLResponse - -app = FastAPI() - - -@app.post("/files/") -async def create_files( - files: List[bytes] = File(description="Multiple files as bytes"), -): - return {"file_sizes": [len(file) for file in files]} - - -@app.post("/uploadfiles/") -async def create_upload_files( - files: List[UploadFile] = File(description="Multiple files as UploadFile"), -): - return {"filenames": [file.filename for file in files]} - - -@app.get("/") -async def main(): - content = """ - -
- - -
-
- - -
- - """ - return HTMLResponse(content=content) diff --git a/docs_src/request_files/tutorial003_an.py b/docs_src/request_files/tutorial003_an.py deleted file mode 100644 index 2238e3c94b..0000000000 --- a/docs_src/request_files/tutorial003_an.py +++ /dev/null @@ -1,40 +0,0 @@ -from typing import List - -from fastapi import FastAPI, File, UploadFile -from fastapi.responses import HTMLResponse -from typing_extensions import Annotated - -app = FastAPI() - - -@app.post("/files/") -async def create_files( - files: Annotated[List[bytes], File(description="Multiple files as bytes")], -): - return {"file_sizes": [len(file) for file in files]} - - -@app.post("/uploadfiles/") -async def create_upload_files( - files: Annotated[ - List[UploadFile], File(description="Multiple files as UploadFile") - ], -): - return {"filenames": [file.filename for file in files]} - - -@app.get("/") -async def main(): - content = """ - -
- - -
-
- - -
- - """ - return HTMLResponse(content=content) diff --git a/docs_src/request_form_models/tutorial001_an.py b/docs_src/request_form_models/tutorial001_an.py deleted file mode 100644 index 30483d4455..0000000000 --- a/docs_src/request_form_models/tutorial001_an.py +++ /dev/null @@ -1,15 +0,0 @@ -from fastapi import FastAPI, Form -from pydantic import BaseModel -from typing_extensions import Annotated - -app = FastAPI() - - -class FormData(BaseModel): - username: str - password: str - - -@app.post("/login/") -async def login(data: Annotated[FormData, Form()]): - return data diff --git a/docs_src/request_form_models/tutorial001.py b/docs_src/request_form_models/tutorial001_py39.py similarity index 100% rename from docs_src/request_form_models/tutorial001.py rename to docs_src/request_form_models/tutorial001_py39.py diff --git a/docs_src/request_form_models/tutorial002_an.py b/docs_src/request_form_models/tutorial002_an.py deleted file mode 100644 index bcb0227959..0000000000 --- a/docs_src/request_form_models/tutorial002_an.py +++ /dev/null @@ -1,16 +0,0 @@ -from fastapi import FastAPI, Form -from pydantic import BaseModel -from typing_extensions import Annotated - -app = FastAPI() - - -class FormData(BaseModel): - username: str - password: str - model_config = {"extra": "forbid"} - - -@app.post("/login/") -async def login(data: Annotated[FormData, Form()]): - return data diff --git a/docs_src/request_form_models/tutorial002_pv1_an.py b/docs_src/request_form_models/tutorial002_pv1_an.py deleted file mode 100644 index fe9dbc344b..0000000000 --- a/docs_src/request_form_models/tutorial002_pv1_an.py +++ /dev/null @@ -1,18 +0,0 @@ -from fastapi import FastAPI, Form -from pydantic import BaseModel -from typing_extensions import Annotated - -app = FastAPI() - - -class FormData(BaseModel): - username: str - password: str - - class Config: - extra = "forbid" - - -@app.post("/login/") -async def login(data: Annotated[FormData, Form()]): - return data diff --git a/docs_src/request_form_models/tutorial002_pv1.py b/docs_src/request_form_models/tutorial002_pv1_py39.py similarity index 100% rename from docs_src/request_form_models/tutorial002_pv1.py rename to docs_src/request_form_models/tutorial002_pv1_py39.py diff --git a/docs_src/request_form_models/tutorial002.py b/docs_src/request_form_models/tutorial002_py39.py similarity index 100% rename from docs_src/request_form_models/tutorial002.py rename to docs_src/request_form_models/tutorial002_py39.py diff --git a/docs_src/request_forms/tutorial001_an.py b/docs_src/request_forms/tutorial001_an.py deleted file mode 100644 index 677fbf2db8..0000000000 --- a/docs_src/request_forms/tutorial001_an.py +++ /dev/null @@ -1,9 +0,0 @@ -from fastapi import FastAPI, Form -from typing_extensions import Annotated - -app = FastAPI() - - -@app.post("/login/") -async def login(username: Annotated[str, Form()], password: Annotated[str, Form()]): - return {"username": username} diff --git a/docs_src/request_forms/tutorial001.py b/docs_src/request_forms/tutorial001_py39.py similarity index 100% rename from docs_src/request_forms/tutorial001.py rename to docs_src/request_forms/tutorial001_py39.py diff --git a/docs_src/request_forms_and_files/tutorial001_an.py b/docs_src/request_forms_and_files/tutorial001_an.py deleted file mode 100644 index 0ea285ac87..0000000000 --- a/docs_src/request_forms_and_files/tutorial001_an.py +++ /dev/null @@ -1,17 +0,0 @@ -from fastapi import FastAPI, File, Form, UploadFile -from typing_extensions import Annotated - -app = FastAPI() - - -@app.post("/files/") -async def create_file( - file: Annotated[bytes, File()], - fileb: Annotated[UploadFile, File()], - token: Annotated[str, Form()], -): - return { - "file_size": len(file), - "token": token, - "fileb_content_type": fileb.content_type, - } diff --git a/docs_src/request_forms_and_files/tutorial001.py b/docs_src/request_forms_and_files/tutorial001_py39.py similarity index 100% rename from docs_src/request_forms_and_files/tutorial001.py rename to docs_src/request_forms_and_files/tutorial001_py39.py diff --git a/docs_src/response_change_status_code/tutorial001.py b/docs_src/response_change_status_code/tutorial001_py39.py similarity index 100% rename from docs_src/response_change_status_code/tutorial001.py rename to docs_src/response_change_status_code/tutorial001_py39.py diff --git a/docs_src/response_cookies/tutorial001.py b/docs_src/response_cookies/tutorial001_py39.py similarity index 100% rename from docs_src/response_cookies/tutorial001.py rename to docs_src/response_cookies/tutorial001_py39.py diff --git a/docs_src/response_cookies/tutorial002.py b/docs_src/response_cookies/tutorial002_py39.py similarity index 100% rename from docs_src/response_cookies/tutorial002.py rename to docs_src/response_cookies/tutorial002_py39.py diff --git a/docs_src/response_directly/tutorial001.py b/docs_src/response_directly/tutorial001_py39.py similarity index 100% rename from docs_src/response_directly/tutorial001.py rename to docs_src/response_directly/tutorial001_py39.py diff --git a/docs_src/response_directly/tutorial002.py b/docs_src/response_directly/tutorial002_py39.py similarity index 100% rename from docs_src/response_directly/tutorial002.py rename to docs_src/response_directly/tutorial002_py39.py diff --git a/docs_src/response_headers/tutorial001.py b/docs_src/response_headers/tutorial001_py39.py similarity index 100% rename from docs_src/response_headers/tutorial001.py rename to docs_src/response_headers/tutorial001_py39.py diff --git a/docs_src/response_headers/tutorial002.py b/docs_src/response_headers/tutorial002_py39.py similarity index 100% rename from docs_src/response_headers/tutorial002.py rename to docs_src/response_headers/tutorial002_py39.py diff --git a/docs_src/response_model/tutorial001.py b/docs_src/response_model/tutorial001.py deleted file mode 100644 index fd1c902a52..0000000000 --- a/docs_src/response_model/tutorial001.py +++ /dev/null @@ -1,27 +0,0 @@ -from typing import Any, List, Union - -from fastapi import FastAPI -from pydantic import BaseModel - -app = FastAPI() - - -class Item(BaseModel): - name: str - description: Union[str, None] = None - price: float - tax: Union[float, None] = None - tags: List[str] = [] - - -@app.post("/items/", response_model=Item) -async def create_item(item: Item) -> Any: - return item - - -@app.get("/items/", response_model=List[Item]) -async def read_items() -> Any: - return [ - {"name": "Portal Gun", "price": 42.0}, - {"name": "Plumbus", "price": 32.0}, - ] diff --git a/docs_src/response_model/tutorial001_01.py b/docs_src/response_model/tutorial001_01.py deleted file mode 100644 index 98d30d540f..0000000000 --- a/docs_src/response_model/tutorial001_01.py +++ /dev/null @@ -1,27 +0,0 @@ -from typing import List, Union - -from fastapi import FastAPI -from pydantic import BaseModel - -app = FastAPI() - - -class Item(BaseModel): - name: str - description: Union[str, None] = None - price: float - tax: Union[float, None] = None - tags: List[str] = [] - - -@app.post("/items/") -async def create_item(item: Item) -> Item: - return item - - -@app.get("/items/") -async def read_items() -> List[Item]: - return [ - Item(name="Portal Gun", price=42.0), - Item(name="Plumbus", price=32.0), - ] diff --git a/docs_src/response_model/tutorial002.py b/docs_src/response_model/tutorial002_py39.py similarity index 100% rename from docs_src/response_model/tutorial002.py rename to docs_src/response_model/tutorial002_py39.py diff --git a/docs_src/response_model/tutorial003_01.py b/docs_src/response_model/tutorial003_01_py39.py similarity index 100% rename from docs_src/response_model/tutorial003_01.py rename to docs_src/response_model/tutorial003_01_py39.py diff --git a/docs_src/response_model/tutorial003_02.py b/docs_src/response_model/tutorial003_02_py39.py similarity index 100% rename from docs_src/response_model/tutorial003_02.py rename to docs_src/response_model/tutorial003_02_py39.py diff --git a/docs_src/response_model/tutorial003_03.py b/docs_src/response_model/tutorial003_03_py39.py similarity index 100% rename from docs_src/response_model/tutorial003_03.py rename to docs_src/response_model/tutorial003_03_py39.py diff --git a/docs_src/response_model/tutorial003_04.py b/docs_src/response_model/tutorial003_04_py39.py similarity index 100% rename from docs_src/response_model/tutorial003_04.py rename to docs_src/response_model/tutorial003_04_py39.py diff --git a/docs_src/response_model/tutorial003_05.py b/docs_src/response_model/tutorial003_05_py39.py similarity index 100% rename from docs_src/response_model/tutorial003_05.py rename to docs_src/response_model/tutorial003_05_py39.py diff --git a/docs_src/response_model/tutorial003.py b/docs_src/response_model/tutorial003_py39.py similarity index 100% rename from docs_src/response_model/tutorial003.py rename to docs_src/response_model/tutorial003_py39.py diff --git a/docs_src/response_model/tutorial004.py b/docs_src/response_model/tutorial004.py deleted file mode 100644 index 10b48039ae..0000000000 --- a/docs_src/response_model/tutorial004.py +++ /dev/null @@ -1,26 +0,0 @@ -from typing import List, Union - -from fastapi import FastAPI -from pydantic import BaseModel - -app = FastAPI() - - -class Item(BaseModel): - name: str - description: Union[str, None] = None - price: float - tax: float = 10.5 - tags: List[str] = [] - - -items = { - "foo": {"name": "Foo", "price": 50.2}, - "bar": {"name": "Bar", "description": "The bartenders", "price": 62, "tax": 20.2}, - "baz": {"name": "Baz", "description": None, "price": 50.2, "tax": 10.5, "tags": []}, -} - - -@app.get("/items/{item_id}", response_model=Item, response_model_exclude_unset=True) -async def read_item(item_id: str): - return items[item_id] diff --git a/docs_src/response_model/tutorial005.py b/docs_src/response_model/tutorial005_py39.py similarity index 100% rename from docs_src/response_model/tutorial005.py rename to docs_src/response_model/tutorial005_py39.py diff --git a/docs_src/response_model/tutorial006.py b/docs_src/response_model/tutorial006_py39.py similarity index 100% rename from docs_src/response_model/tutorial006.py rename to docs_src/response_model/tutorial006_py39.py diff --git a/docs_src/response_status_code/tutorial001.py b/docs_src/response_status_code/tutorial001_py39.py similarity index 100% rename from docs_src/response_status_code/tutorial001.py rename to docs_src/response_status_code/tutorial001_py39.py diff --git a/docs_src/response_status_code/tutorial002.py b/docs_src/response_status_code/tutorial002_py39.py similarity index 100% rename from docs_src/response_status_code/tutorial002.py rename to docs_src/response_status_code/tutorial002_py39.py diff --git a/docs_src/schema_extra_example/tutorial001_pv1.py b/docs_src/schema_extra_example/tutorial001_pv1_py39.py similarity index 100% rename from docs_src/schema_extra_example/tutorial001_pv1.py rename to docs_src/schema_extra_example/tutorial001_pv1_py39.py diff --git a/docs_src/schema_extra_example/tutorial001.py b/docs_src/schema_extra_example/tutorial001_py39.py similarity index 100% rename from docs_src/schema_extra_example/tutorial001.py rename to docs_src/schema_extra_example/tutorial001_py39.py diff --git a/docs_src/schema_extra_example/tutorial002.py b/docs_src/schema_extra_example/tutorial002_py39.py similarity index 100% rename from docs_src/schema_extra_example/tutorial002.py rename to docs_src/schema_extra_example/tutorial002_py39.py diff --git a/docs_src/schema_extra_example/tutorial003_an.py b/docs_src/schema_extra_example/tutorial003_an.py deleted file mode 100644 index 23675aba14..0000000000 --- a/docs_src/schema_extra_example/tutorial003_an.py +++ /dev/null @@ -1,35 +0,0 @@ -from typing import Union - -from fastapi import Body, FastAPI -from pydantic import BaseModel -from typing_extensions import Annotated - -app = FastAPI() - - -class Item(BaseModel): - name: str - description: Union[str, None] = None - price: float - tax: Union[float, None] = None - - -@app.put("/items/{item_id}") -async def update_item( - item_id: int, - item: Annotated[ - Item, - Body( - examples=[ - { - "name": "Foo", - "description": "A very nice Item", - "price": 35.4, - "tax": 3.2, - } - ], - ), - ], -): - results = {"item_id": item_id, "item": item} - return results diff --git a/docs_src/schema_extra_example/tutorial003.py b/docs_src/schema_extra_example/tutorial003_py39.py similarity index 100% rename from docs_src/schema_extra_example/tutorial003.py rename to docs_src/schema_extra_example/tutorial003_py39.py diff --git a/docs_src/schema_extra_example/tutorial004_an.py b/docs_src/schema_extra_example/tutorial004_an.py deleted file mode 100644 index e817302a22..0000000000 --- a/docs_src/schema_extra_example/tutorial004_an.py +++ /dev/null @@ -1,44 +0,0 @@ -from typing import Union - -from fastapi import Body, FastAPI -from pydantic import BaseModel -from typing_extensions import Annotated - -app = FastAPI() - - -class Item(BaseModel): - name: str - description: Union[str, None] = None - price: float - tax: Union[float, None] = None - - -@app.put("/items/{item_id}") -async def update_item( - *, - item_id: int, - item: Annotated[ - Item, - Body( - examples=[ - { - "name": "Foo", - "description": "A very nice Item", - "price": 35.4, - "tax": 3.2, - }, - { - "name": "Bar", - "price": "35.4", - }, - { - "name": "Baz", - "price": "thirty five point four", - }, - ], - ), - ], -): - results = {"item_id": item_id, "item": item} - return results diff --git a/docs_src/schema_extra_example/tutorial004.py b/docs_src/schema_extra_example/tutorial004_py39.py similarity index 100% rename from docs_src/schema_extra_example/tutorial004.py rename to docs_src/schema_extra_example/tutorial004_py39.py diff --git a/docs_src/schema_extra_example/tutorial005_an.py b/docs_src/schema_extra_example/tutorial005_an.py deleted file mode 100644 index 4b2d9c662b..0000000000 --- a/docs_src/schema_extra_example/tutorial005_an.py +++ /dev/null @@ -1,55 +0,0 @@ -from typing import Union - -from fastapi import Body, FastAPI -from pydantic import BaseModel -from typing_extensions import Annotated - -app = FastAPI() - - -class Item(BaseModel): - name: str - description: Union[str, None] = None - price: float - tax: Union[float, None] = None - - -@app.put("/items/{item_id}") -async def update_item( - *, - item_id: int, - item: Annotated[ - Item, - Body( - openapi_examples={ - "normal": { - "summary": "A normal example", - "description": "A **normal** item works correctly.", - "value": { - "name": "Foo", - "description": "A very nice Item", - "price": 35.4, - "tax": 3.2, - }, - }, - "converted": { - "summary": "An example with converted data", - "description": "FastAPI can convert price `strings` to actual `numbers` automatically", - "value": { - "name": "Bar", - "price": "35.4", - }, - }, - "invalid": { - "summary": "Invalid data is rejected with an error", - "value": { - "name": "Baz", - "price": "thirty five point four", - }, - }, - }, - ), - ], -): - results = {"item_id": item_id, "item": item} - return results diff --git a/docs_src/schema_extra_example/tutorial005.py b/docs_src/schema_extra_example/tutorial005_py39.py similarity index 100% rename from docs_src/schema_extra_example/tutorial005.py rename to docs_src/schema_extra_example/tutorial005_py39.py diff --git a/docs_src/security/tutorial001_an.py b/docs_src/security/tutorial001_an.py deleted file mode 100644 index dac915b7ca..0000000000 --- a/docs_src/security/tutorial001_an.py +++ /dev/null @@ -1,12 +0,0 @@ -from fastapi import Depends, FastAPI -from fastapi.security import OAuth2PasswordBearer -from typing_extensions import Annotated - -app = FastAPI() - -oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token") - - -@app.get("/items/") -async def read_items(token: Annotated[str, Depends(oauth2_scheme)]): - return {"token": token} diff --git a/docs_src/security/tutorial001.py b/docs_src/security/tutorial001_py39.py similarity index 100% rename from docs_src/security/tutorial001.py rename to docs_src/security/tutorial001_py39.py diff --git a/docs_src/security/tutorial002_an.py b/docs_src/security/tutorial002_an.py deleted file mode 100644 index 291b3bf530..0000000000 --- a/docs_src/security/tutorial002_an.py +++ /dev/null @@ -1,33 +0,0 @@ -from typing import Union - -from fastapi import Depends, FastAPI -from fastapi.security import OAuth2PasswordBearer -from pydantic import BaseModel -from typing_extensions import Annotated - -app = FastAPI() - -oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token") - - -class User(BaseModel): - username: str - email: Union[str, None] = None - full_name: Union[str, None] = None - disabled: Union[bool, None] = None - - -def fake_decode_token(token): - return User( - username=token + "fakedecoded", email="john@example.com", full_name="John Doe" - ) - - -async def get_current_user(token: Annotated[str, Depends(oauth2_scheme)]): - user = fake_decode_token(token) - return user - - -@app.get("/users/me") -async def read_users_me(current_user: Annotated[User, Depends(get_current_user)]): - return current_user diff --git a/docs_src/security/tutorial002.py b/docs_src/security/tutorial002_py39.py similarity index 100% rename from docs_src/security/tutorial002.py rename to docs_src/security/tutorial002_py39.py diff --git a/docs_src/security/tutorial003_an.py b/docs_src/security/tutorial003_an.py deleted file mode 100644 index 1b7056a209..0000000000 --- a/docs_src/security/tutorial003_an.py +++ /dev/null @@ -1,95 +0,0 @@ -from typing import Union - -from fastapi import Depends, FastAPI, HTTPException, status -from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm -from pydantic import BaseModel -from typing_extensions import Annotated - -fake_users_db = { - "johndoe": { - "username": "johndoe", - "full_name": "John Doe", - "email": "johndoe@example.com", - "hashed_password": "fakehashedsecret", - "disabled": False, - }, - "alice": { - "username": "alice", - "full_name": "Alice Wonderson", - "email": "alice@example.com", - "hashed_password": "fakehashedsecret2", - "disabled": True, - }, -} - -app = FastAPI() - - -def fake_hash_password(password: str): - return "fakehashed" + password - - -oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token") - - -class User(BaseModel): - username: str - email: Union[str, None] = None - full_name: Union[str, None] = None - disabled: Union[bool, None] = None - - -class UserInDB(User): - hashed_password: str - - -def get_user(db, username: str): - if username in db: - user_dict = db[username] - return UserInDB(**user_dict) - - -def fake_decode_token(token): - # This doesn't provide any security at all - # Check the next version - user = get_user(fake_users_db, token) - return user - - -async def get_current_user(token: Annotated[str, Depends(oauth2_scheme)]): - user = fake_decode_token(token) - if not user: - raise HTTPException( - status_code=status.HTTP_401_UNAUTHORIZED, - detail="Not authenticated", - headers={"WWW-Authenticate": "Bearer"}, - ) - return user - - -async def get_current_active_user( - current_user: Annotated[User, Depends(get_current_user)], -): - if current_user.disabled: - raise HTTPException(status_code=400, detail="Inactive user") - return current_user - - -@app.post("/token") -async def login(form_data: Annotated[OAuth2PasswordRequestForm, Depends()]): - user_dict = fake_users_db.get(form_data.username) - if not user_dict: - raise HTTPException(status_code=400, detail="Incorrect username or password") - user = UserInDB(**user_dict) - hashed_password = fake_hash_password(form_data.password) - if not hashed_password == user.hashed_password: - raise HTTPException(status_code=400, detail="Incorrect username or password") - - return {"access_token": user.username, "token_type": "bearer"} - - -@app.get("/users/me") -async def read_users_me( - current_user: Annotated[User, Depends(get_current_active_user)], -): - return current_user diff --git a/docs_src/security/tutorial003.py b/docs_src/security/tutorial003_py39.py similarity index 100% rename from docs_src/security/tutorial003.py rename to docs_src/security/tutorial003_py39.py diff --git a/docs_src/security/tutorial004_an.py b/docs_src/security/tutorial004_an.py deleted file mode 100644 index 018234e300..0000000000 --- a/docs_src/security/tutorial004_an.py +++ /dev/null @@ -1,148 +0,0 @@ -from datetime import datetime, timedelta, timezone -from typing import Union - -import jwt -from fastapi import Depends, FastAPI, HTTPException, status -from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm -from jwt.exceptions import InvalidTokenError -from pwdlib import PasswordHash -from pydantic import BaseModel -from typing_extensions import Annotated - -# to get a string like this run: -# openssl rand -hex 32 -SECRET_KEY = "09d25e094faa6ca2556c818166b7a9563b93f7099f6f0f4caa6cf63b88e8d3e7" -ALGORITHM = "HS256" -ACCESS_TOKEN_EXPIRE_MINUTES = 30 - - -fake_users_db = { - "johndoe": { - "username": "johndoe", - "full_name": "John Doe", - "email": "johndoe@example.com", - "hashed_password": "$argon2id$v=19$m=65536,t=3,p=4$wagCPXjifgvUFBzq4hqe3w$CYaIb8sB+wtD+Vu/P4uod1+Qof8h+1g7bbDlBID48Rc", - "disabled": False, - } -} - - -class Token(BaseModel): - access_token: str - token_type: str - - -class TokenData(BaseModel): - username: Union[str, None] = None - - -class User(BaseModel): - username: str - email: Union[str, None] = None - full_name: Union[str, None] = None - disabled: Union[bool, None] = None - - -class UserInDB(User): - hashed_password: str - - -password_hash = PasswordHash.recommended() - -oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token") - -app = FastAPI() - - -def verify_password(plain_password, hashed_password): - return password_hash.verify(plain_password, hashed_password) - - -def get_password_hash(password): - return password_hash.hash(password) - - -def get_user(db, username: str): - if username in db: - user_dict = db[username] - return UserInDB(**user_dict) - - -def authenticate_user(fake_db, username: str, password: str): - user = get_user(fake_db, username) - if not user: - return False - if not verify_password(password, user.hashed_password): - return False - return user - - -def create_access_token(data: dict, expires_delta: Union[timedelta, None] = None): - to_encode = data.copy() - if expires_delta: - expire = datetime.now(timezone.utc) + expires_delta - else: - expire = datetime.now(timezone.utc) + timedelta(minutes=15) - to_encode.update({"exp": expire}) - encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM) - return encoded_jwt - - -async def get_current_user(token: Annotated[str, Depends(oauth2_scheme)]): - credentials_exception = HTTPException( - status_code=status.HTTP_401_UNAUTHORIZED, - detail="Could not validate credentials", - headers={"WWW-Authenticate": "Bearer"}, - ) - try: - payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM]) - username = payload.get("sub") - if username is None: - raise credentials_exception - token_data = TokenData(username=username) - except InvalidTokenError: - raise credentials_exception - user = get_user(fake_users_db, username=token_data.username) - if user is None: - raise credentials_exception - return user - - -async def get_current_active_user( - current_user: Annotated[User, Depends(get_current_user)], -): - if current_user.disabled: - raise HTTPException(status_code=400, detail="Inactive user") - return current_user - - -@app.post("/token") -async def login_for_access_token( - form_data: Annotated[OAuth2PasswordRequestForm, Depends()], -) -> Token: - user = authenticate_user(fake_users_db, form_data.username, form_data.password) - if not user: - raise HTTPException( - status_code=status.HTTP_401_UNAUTHORIZED, - detail="Incorrect username or password", - headers={"WWW-Authenticate": "Bearer"}, - ) - access_token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES) - access_token = create_access_token( - data={"sub": user.username}, expires_delta=access_token_expires - ) - return Token(access_token=access_token, token_type="bearer") - - -@app.get("/users/me/", response_model=User) -async def read_users_me( - current_user: Annotated[User, Depends(get_current_active_user)], -): - return current_user - - -@app.get("/users/me/items/") -async def read_own_items( - current_user: Annotated[User, Depends(get_current_active_user)], -): - return [{"item_id": "Foo", "owner": current_user.username}] diff --git a/docs_src/security/tutorial004.py b/docs_src/security/tutorial004_py39.py similarity index 100% rename from docs_src/security/tutorial004.py rename to docs_src/security/tutorial004_py39.py diff --git a/docs_src/security/tutorial005.py b/docs_src/security/tutorial005.py deleted file mode 100644 index fdd73bcd8a..0000000000 --- a/docs_src/security/tutorial005.py +++ /dev/null @@ -1,177 +0,0 @@ -from datetime import datetime, timedelta, timezone -from typing import List, Union - -import jwt -from fastapi import Depends, FastAPI, HTTPException, Security, status -from fastapi.security import ( - OAuth2PasswordBearer, - OAuth2PasswordRequestForm, - SecurityScopes, -) -from jwt.exceptions import InvalidTokenError -from pwdlib import PasswordHash -from pydantic import BaseModel, ValidationError - -# to get a string like this run: -# openssl rand -hex 32 -SECRET_KEY = "09d25e094faa6ca2556c818166b7a9563b93f7099f6f0f4caa6cf63b88e8d3e7" -ALGORITHM = "HS256" -ACCESS_TOKEN_EXPIRE_MINUTES = 30 - - -fake_users_db = { - "johndoe": { - "username": "johndoe", - "full_name": "John Doe", - "email": "johndoe@example.com", - "hashed_password": "$argon2id$v=19$m=65536,t=3,p=4$wagCPXjifgvUFBzq4hqe3w$CYaIb8sB+wtD+Vu/P4uod1+Qof8h+1g7bbDlBID48Rc", - "disabled": False, - }, - "alice": { - "username": "alice", - "full_name": "Alice Chains", - "email": "alicechains@example.com", - "hashed_password": "$argon2id$v=19$m=65536,t=3,p=4$g2/AV1zwopqUntPKJavBFw$BwpRGDCyUHLvHICnwijyX8ROGoiUPwNKZ7915MeYfCE", - "disabled": True, - }, -} - - -class Token(BaseModel): - access_token: str - token_type: str - - -class TokenData(BaseModel): - username: Union[str, None] = None - scopes: List[str] = [] - - -class User(BaseModel): - username: str - email: Union[str, None] = None - full_name: Union[str, None] = None - disabled: Union[bool, None] = None - - -class UserInDB(User): - hashed_password: str - - -password_hash = PasswordHash.recommended() - -oauth2_scheme = OAuth2PasswordBearer( - tokenUrl="token", - scopes={"me": "Read information about the current user.", "items": "Read items."}, -) - -app = FastAPI() - - -def verify_password(plain_password, hashed_password): - return password_hash.verify(plain_password, hashed_password) - - -def get_password_hash(password): - return password_hash.hash(password) - - -def get_user(db, username: str): - if username in db: - user_dict = db[username] - return UserInDB(**user_dict) - - -def authenticate_user(fake_db, username: str, password: str): - user = get_user(fake_db, username) - if not user: - return False - if not verify_password(password, user.hashed_password): - return False - return user - - -def create_access_token(data: dict, expires_delta: Union[timedelta, None] = None): - to_encode = data.copy() - if expires_delta: - expire = datetime.now(timezone.utc) + expires_delta - else: - expire = datetime.now(timezone.utc) + timedelta(minutes=15) - to_encode.update({"exp": expire}) - encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM) - return encoded_jwt - - -async def get_current_user( - security_scopes: SecurityScopes, token: str = Depends(oauth2_scheme) -): - if security_scopes.scopes: - authenticate_value = f'Bearer scope="{security_scopes.scope_str}"' - else: - authenticate_value = "Bearer" - credentials_exception = HTTPException( - status_code=status.HTTP_401_UNAUTHORIZED, - detail="Could not validate credentials", - headers={"WWW-Authenticate": authenticate_value}, - ) - try: - payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM]) - username: str = payload.get("sub") - if username is None: - raise credentials_exception - scope: str = payload.get("scope", "") - token_scopes = scope.split(" ") - token_data = TokenData(scopes=token_scopes, username=username) - except (InvalidTokenError, ValidationError): - raise credentials_exception - user = get_user(fake_users_db, username=token_data.username) - if user is None: - raise credentials_exception - for scope in security_scopes.scopes: - if scope not in token_data.scopes: - raise HTTPException( - status_code=status.HTTP_401_UNAUTHORIZED, - detail="Not enough permissions", - headers={"WWW-Authenticate": authenticate_value}, - ) - return user - - -async def get_current_active_user( - current_user: User = Security(get_current_user, scopes=["me"]), -): - if current_user.disabled: - raise HTTPException(status_code=400, detail="Inactive user") - return current_user - - -@app.post("/token") -async def login_for_access_token( - form_data: OAuth2PasswordRequestForm = Depends(), -) -> Token: - user = authenticate_user(fake_users_db, form_data.username, form_data.password) - if not user: - raise HTTPException(status_code=400, detail="Incorrect username or password") - access_token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES) - access_token = create_access_token( - data={"sub": user.username, "scope": " ".join(form_data.scopes)}, - expires_delta=access_token_expires, - ) - return Token(access_token=access_token, token_type="bearer") - - -@app.get("/users/me/", response_model=User) -async def read_users_me(current_user: User = Depends(get_current_active_user)): - return current_user - - -@app.get("/users/me/items/") -async def read_own_items( - current_user: User = Security(get_current_active_user, scopes=["items"]), -): - return [{"item_id": "Foo", "owner": current_user.username}] - - -@app.get("/status/") -async def read_system_status(current_user: User = Depends(get_current_user)): - return {"status": "ok"} diff --git a/docs_src/security/tutorial005_an.py b/docs_src/security/tutorial005_an.py deleted file mode 100644 index e1d7b4f62a..0000000000 --- a/docs_src/security/tutorial005_an.py +++ /dev/null @@ -1,180 +0,0 @@ -from datetime import datetime, timedelta, timezone -from typing import List, Union - -import jwt -from fastapi import Depends, FastAPI, HTTPException, Security, status -from fastapi.security import ( - OAuth2PasswordBearer, - OAuth2PasswordRequestForm, - SecurityScopes, -) -from jwt.exceptions import InvalidTokenError -from pwdlib import PasswordHash -from pydantic import BaseModel, ValidationError -from typing_extensions import Annotated - -# to get a string like this run: -# openssl rand -hex 32 -SECRET_KEY = "09d25e094faa6ca2556c818166b7a9563b93f7099f6f0f4caa6cf63b88e8d3e7" -ALGORITHM = "HS256" -ACCESS_TOKEN_EXPIRE_MINUTES = 30 - - -fake_users_db = { - "johndoe": { - "username": "johndoe", - "full_name": "John Doe", - "email": "johndoe@example.com", - "hashed_password": "$argon2id$v=19$m=65536,t=3,p=4$wagCPXjifgvUFBzq4hqe3w$CYaIb8sB+wtD+Vu/P4uod1+Qof8h+1g7bbDlBID48Rc", - "disabled": False, - }, - "alice": { - "username": "alice", - "full_name": "Alice Chains", - "email": "alicechains@example.com", - "hashed_password": "$argon2id$v=19$m=65536,t=3,p=4$g2/AV1zwopqUntPKJavBFw$BwpRGDCyUHLvHICnwijyX8ROGoiUPwNKZ7915MeYfCE", - "disabled": True, - }, -} - - -class Token(BaseModel): - access_token: str - token_type: str - - -class TokenData(BaseModel): - username: Union[str, None] = None - scopes: List[str] = [] - - -class User(BaseModel): - username: str - email: Union[str, None] = None - full_name: Union[str, None] = None - disabled: Union[bool, None] = None - - -class UserInDB(User): - hashed_password: str - - -password_hash = PasswordHash.recommended() - -oauth2_scheme = OAuth2PasswordBearer( - tokenUrl="token", - scopes={"me": "Read information about the current user.", "items": "Read items."}, -) - -app = FastAPI() - - -def verify_password(plain_password, hashed_password): - return password_hash.verify(plain_password, hashed_password) - - -def get_password_hash(password): - return password_hash.hash(password) - - -def get_user(db, username: str): - if username in db: - user_dict = db[username] - return UserInDB(**user_dict) - - -def authenticate_user(fake_db, username: str, password: str): - user = get_user(fake_db, username) - if not user: - return False - if not verify_password(password, user.hashed_password): - return False - return user - - -def create_access_token(data: dict, expires_delta: Union[timedelta, None] = None): - to_encode = data.copy() - if expires_delta: - expire = datetime.now(timezone.utc) + expires_delta - else: - expire = datetime.now(timezone.utc) + timedelta(minutes=15) - to_encode.update({"exp": expire}) - encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM) - return encoded_jwt - - -async def get_current_user( - security_scopes: SecurityScopes, token: Annotated[str, Depends(oauth2_scheme)] -): - if security_scopes.scopes: - authenticate_value = f'Bearer scope="{security_scopes.scope_str}"' - else: - authenticate_value = "Bearer" - credentials_exception = HTTPException( - status_code=status.HTTP_401_UNAUTHORIZED, - detail="Could not validate credentials", - headers={"WWW-Authenticate": authenticate_value}, - ) - try: - payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM]) - username = payload.get("sub") - if username is None: - raise credentials_exception - scope: str = payload.get("scope", "") - token_scopes = scope.split(" ") - token_data = TokenData(scopes=token_scopes, username=username) - except (InvalidTokenError, ValidationError): - raise credentials_exception - user = get_user(fake_users_db, username=token_data.username) - if user is None: - raise credentials_exception - for scope in security_scopes.scopes: - if scope not in token_data.scopes: - raise HTTPException( - status_code=status.HTTP_401_UNAUTHORIZED, - detail="Not enough permissions", - headers={"WWW-Authenticate": authenticate_value}, - ) - return user - - -async def get_current_active_user( - current_user: Annotated[User, Security(get_current_user, scopes=["me"])], -): - if current_user.disabled: - raise HTTPException(status_code=400, detail="Inactive user") - return current_user - - -@app.post("/token") -async def login_for_access_token( - form_data: Annotated[OAuth2PasswordRequestForm, Depends()], -) -> Token: - user = authenticate_user(fake_users_db, form_data.username, form_data.password) - if not user: - raise HTTPException(status_code=400, detail="Incorrect username or password") - access_token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES) - access_token = create_access_token( - data={"sub": user.username, "scope": " ".join(form_data.scopes)}, - expires_delta=access_token_expires, - ) - return Token(access_token=access_token, token_type="bearer") - - -@app.get("/users/me/", response_model=User) -async def read_users_me( - current_user: Annotated[User, Depends(get_current_active_user)], -): - return current_user - - -@app.get("/users/me/items/") -async def read_own_items( - current_user: Annotated[User, Security(get_current_active_user, scopes=["items"])], -): - return [{"item_id": "Foo", "owner": current_user.username}] - - -@app.get("/status/") -async def read_system_status(current_user: Annotated[User, Depends(get_current_user)]): - return {"status": "ok"} diff --git a/docs_src/security/tutorial006_an.py b/docs_src/security/tutorial006_an.py deleted file mode 100644 index 985e4b2ad2..0000000000 --- a/docs_src/security/tutorial006_an.py +++ /dev/null @@ -1,12 +0,0 @@ -from fastapi import Depends, FastAPI -from fastapi.security import HTTPBasic, HTTPBasicCredentials -from typing_extensions import Annotated - -app = FastAPI() - -security = HTTPBasic() - - -@app.get("/users/me") -def read_current_user(credentials: Annotated[HTTPBasicCredentials, Depends(security)]): - return {"username": credentials.username, "password": credentials.password} diff --git a/docs_src/security/tutorial006.py b/docs_src/security/tutorial006_py39.py similarity index 100% rename from docs_src/security/tutorial006.py rename to docs_src/security/tutorial006_py39.py diff --git a/docs_src/security/tutorial007_an.py b/docs_src/security/tutorial007_an.py deleted file mode 100644 index 0d211dfde5..0000000000 --- a/docs_src/security/tutorial007_an.py +++ /dev/null @@ -1,36 +0,0 @@ -import secrets - -from fastapi import Depends, FastAPI, HTTPException, status -from fastapi.security import HTTPBasic, HTTPBasicCredentials -from typing_extensions import Annotated - -app = FastAPI() - -security = HTTPBasic() - - -def get_current_username( - credentials: Annotated[HTTPBasicCredentials, Depends(security)], -): - current_username_bytes = credentials.username.encode("utf8") - correct_username_bytes = b"stanleyjobson" - is_correct_username = secrets.compare_digest( - current_username_bytes, correct_username_bytes - ) - current_password_bytes = credentials.password.encode("utf8") - correct_password_bytes = b"swordfish" - is_correct_password = secrets.compare_digest( - current_password_bytes, correct_password_bytes - ) - if not (is_correct_username and is_correct_password): - raise HTTPException( - status_code=status.HTTP_401_UNAUTHORIZED, - detail="Incorrect username or password", - headers={"WWW-Authenticate": "Basic"}, - ) - return credentials.username - - -@app.get("/users/me") -def read_current_user(username: Annotated[str, Depends(get_current_username)]): - return {"username": username} diff --git a/docs_src/security/tutorial007.py b/docs_src/security/tutorial007_py39.py similarity index 100% rename from docs_src/security/tutorial007.py rename to docs_src/security/tutorial007_py39.py diff --git a/docs_src/separate_openapi_schemas/tutorial001.py b/docs_src/separate_openapi_schemas/tutorial001.py deleted file mode 100644 index 415eef8e28..0000000000 --- a/docs_src/separate_openapi_schemas/tutorial001.py +++ /dev/null @@ -1,28 +0,0 @@ -from typing import List, Union - -from fastapi import FastAPI -from pydantic import BaseModel - - -class Item(BaseModel): - name: str - description: Union[str, None] = None - - -app = FastAPI() - - -@app.post("/items/") -def create_item(item: Item): - return item - - -@app.get("/items/") -def read_items() -> List[Item]: - return [ - Item( - name="Portal Gun", - description="Device to travel through the multi-rick-verse", - ), - Item(name="Plumbus"), - ] diff --git a/docs_src/separate_openapi_schemas/tutorial002.py b/docs_src/separate_openapi_schemas/tutorial002.py deleted file mode 100644 index 7df93783b9..0000000000 --- a/docs_src/separate_openapi_schemas/tutorial002.py +++ /dev/null @@ -1,28 +0,0 @@ -from typing import List, Union - -from fastapi import FastAPI -from pydantic import BaseModel - - -class Item(BaseModel): - name: str - description: Union[str, None] = None - - -app = FastAPI(separate_input_output_schemas=False) - - -@app.post("/items/") -def create_item(item: Item): - return item - - -@app.get("/items/") -def read_items() -> List[Item]: - return [ - Item( - name="Portal Gun", - description="Device to travel through the multi-rick-verse", - ), - Item(name="Plumbus"), - ] diff --git a/docs_src/bigger_applications/app_an/internal/__init__.py b/docs_src/settings/app01_py39/__init__.py similarity index 100% rename from docs_src/bigger_applications/app_an/internal/__init__.py rename to docs_src/settings/app01_py39/__init__.py diff --git a/docs_src/settings/app01/config.py b/docs_src/settings/app01_py39/config.py similarity index 100% rename from docs_src/settings/app01/config.py rename to docs_src/settings/app01_py39/config.py diff --git a/docs_src/settings/app01/main.py b/docs_src/settings/app01_py39/main.py similarity index 100% rename from docs_src/settings/app01/main.py rename to docs_src/settings/app01_py39/main.py diff --git a/docs_src/settings/app02_an/__init__.py b/docs_src/settings/app02_an/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/docs_src/settings/app02_an/config.py b/docs_src/settings/app02_an/config.py deleted file mode 100644 index e17b5035dc..0000000000 --- a/docs_src/settings/app02_an/config.py +++ /dev/null @@ -1,7 +0,0 @@ -from pydantic_settings import BaseSettings - - -class Settings(BaseSettings): - app_name: str = "Awesome API" - admin_email: str - items_per_user: int = 50 diff --git a/docs_src/settings/app02_an/main.py b/docs_src/settings/app02_an/main.py deleted file mode 100644 index 3a578cc338..0000000000 --- a/docs_src/settings/app02_an/main.py +++ /dev/null @@ -1,22 +0,0 @@ -from functools import lru_cache - -from fastapi import Depends, FastAPI -from typing_extensions import Annotated - -from .config import Settings - -app = FastAPI() - - -@lru_cache -def get_settings(): - return Settings() - - -@app.get("/info") -async def info(settings: Annotated[Settings, Depends(get_settings)]): - return { - "app_name": settings.app_name, - "admin_email": settings.admin_email, - "items_per_user": settings.items_per_user, - } diff --git a/docs_src/settings/app02_an/test_main.py b/docs_src/settings/app02_an/test_main.py deleted file mode 100644 index 7a04d7e8ee..0000000000 --- a/docs_src/settings/app02_an/test_main.py +++ /dev/null @@ -1,23 +0,0 @@ -from fastapi.testclient import TestClient - -from .config import Settings -from .main import app, get_settings - -client = TestClient(app) - - -def get_settings_override(): - return Settings(admin_email="testing_admin@example.com") - - -app.dependency_overrides[get_settings] = get_settings_override - - -def test_app(): - response = client.get("/info") - data = response.json() - assert data == { - "app_name": "Awesome API", - "admin_email": "testing_admin@example.com", - "items_per_user": 50, - } diff --git a/docs_src/bigger_applications/app_an/routers/__init__.py b/docs_src/settings/app02_py39/__init__.py similarity index 100% rename from docs_src/bigger_applications/app_an/routers/__init__.py rename to docs_src/settings/app02_py39/__init__.py diff --git a/docs_src/settings/app02/config.py b/docs_src/settings/app02_py39/config.py similarity index 100% rename from docs_src/settings/app02/config.py rename to docs_src/settings/app02_py39/config.py diff --git a/docs_src/settings/app02/main.py b/docs_src/settings/app02_py39/main.py similarity index 100% rename from docs_src/settings/app02/main.py rename to docs_src/settings/app02_py39/main.py diff --git a/docs_src/settings/app02/test_main.py b/docs_src/settings/app02_py39/test_main.py similarity index 100% rename from docs_src/settings/app02/test_main.py rename to docs_src/settings/app02_py39/test_main.py diff --git a/docs_src/settings/app03/__init__.py b/docs_src/settings/app03/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/docs_src/settings/app03_an/__init__.py b/docs_src/settings/app03_an/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/docs_src/settings/app03_an/config.py b/docs_src/settings/app03_an/config.py deleted file mode 100644 index 08f8f88c28..0000000000 --- a/docs_src/settings/app03_an/config.py +++ /dev/null @@ -1,9 +0,0 @@ -from pydantic_settings import BaseSettings, SettingsConfigDict - - -class Settings(BaseSettings): - app_name: str = "Awesome API" - admin_email: str - items_per_user: int = 50 - - model_config = SettingsConfigDict(env_file=".env") diff --git a/docs_src/settings/app03_an/config_pv1.py b/docs_src/settings/app03_an/config_pv1.py deleted file mode 100644 index e1c3ee3006..0000000000 --- a/docs_src/settings/app03_an/config_pv1.py +++ /dev/null @@ -1,10 +0,0 @@ -from pydantic import BaseSettings - - -class Settings(BaseSettings): - app_name: str = "Awesome API" - admin_email: str - items_per_user: int = 50 - - class Config: - env_file = ".env" diff --git a/docs_src/settings/app03_an/main.py b/docs_src/settings/app03_an/main.py deleted file mode 100644 index 62f3476396..0000000000 --- a/docs_src/settings/app03_an/main.py +++ /dev/null @@ -1,22 +0,0 @@ -from functools import lru_cache - -from fastapi import Depends, FastAPI -from typing_extensions import Annotated - -from . import config - -app = FastAPI() - - -@lru_cache -def get_settings(): - return config.Settings() - - -@app.get("/info") -async def info(settings: Annotated[config.Settings, Depends(get_settings)]): - return { - "app_name": settings.app_name, - "admin_email": settings.admin_email, - "items_per_user": settings.items_per_user, - } diff --git a/docs_src/settings/app01/__init__.py b/docs_src/settings/app03_py39/__init__.py similarity index 100% rename from docs_src/settings/app01/__init__.py rename to docs_src/settings/app03_py39/__init__.py diff --git a/docs_src/settings/app03/config.py b/docs_src/settings/app03_py39/config.py similarity index 100% rename from docs_src/settings/app03/config.py rename to docs_src/settings/app03_py39/config.py diff --git a/docs_src/settings/app03/config_pv1.py b/docs_src/settings/app03_py39/config_pv1.py similarity index 100% rename from docs_src/settings/app03/config_pv1.py rename to docs_src/settings/app03_py39/config_pv1.py diff --git a/docs_src/settings/app03/main.py b/docs_src/settings/app03_py39/main.py similarity index 100% rename from docs_src/settings/app03/main.py rename to docs_src/settings/app03_py39/main.py diff --git a/docs_src/settings/tutorial001_pv1.py b/docs_src/settings/tutorial001_pv1_py39.py similarity index 100% rename from docs_src/settings/tutorial001_pv1.py rename to docs_src/settings/tutorial001_pv1_py39.py diff --git a/docs_src/settings/tutorial001.py b/docs_src/settings/tutorial001_py39.py similarity index 100% rename from docs_src/settings/tutorial001.py rename to docs_src/settings/tutorial001_py39.py diff --git a/docs_src/sql_databases/tutorial001.py b/docs_src/sql_databases/tutorial001.py deleted file mode 100644 index be86ec0eeb..0000000000 --- a/docs_src/sql_databases/tutorial001.py +++ /dev/null @@ -1,71 +0,0 @@ -from typing import List, Union - -from fastapi import Depends, FastAPI, HTTPException, Query -from sqlmodel import Field, Session, SQLModel, create_engine, select - - -class Hero(SQLModel, table=True): - id: Union[int, None] = Field(default=None, primary_key=True) - name: str = Field(index=True) - age: Union[int, None] = Field(default=None, index=True) - secret_name: str - - -sqlite_file_name = "database.db" -sqlite_url = f"sqlite:///{sqlite_file_name}" - -connect_args = {"check_same_thread": False} -engine = create_engine(sqlite_url, connect_args=connect_args) - - -def create_db_and_tables(): - SQLModel.metadata.create_all(engine) - - -def get_session(): - with Session(engine) as session: - yield session - - -app = FastAPI() - - -@app.on_event("startup") -def on_startup(): - create_db_and_tables() - - -@app.post("/heroes/") -def create_hero(hero: Hero, session: Session = Depends(get_session)) -> Hero: - session.add(hero) - session.commit() - session.refresh(hero) - return hero - - -@app.get("/heroes/") -def read_heroes( - session: Session = Depends(get_session), - offset: int = 0, - limit: int = Query(default=100, le=100), -) -> List[Hero]: - heroes = session.exec(select(Hero).offset(offset).limit(limit)).all() - return heroes - - -@app.get("/heroes/{hero_id}") -def read_hero(hero_id: int, session: Session = Depends(get_session)) -> Hero: - hero = session.get(Hero, hero_id) - if not hero: - raise HTTPException(status_code=404, detail="Hero not found") - return hero - - -@app.delete("/heroes/{hero_id}") -def delete_hero(hero_id: int, session: Session = Depends(get_session)): - hero = session.get(Hero, hero_id) - if not hero: - raise HTTPException(status_code=404, detail="Hero not found") - session.delete(hero) - session.commit() - return {"ok": True} diff --git a/docs_src/sql_databases/tutorial001_an.py b/docs_src/sql_databases/tutorial001_an.py deleted file mode 100644 index 8c000d31c7..0000000000 --- a/docs_src/sql_databases/tutorial001_an.py +++ /dev/null @@ -1,74 +0,0 @@ -from typing import List, Union - -from fastapi import Depends, FastAPI, HTTPException, Query -from sqlmodel import Field, Session, SQLModel, create_engine, select -from typing_extensions import Annotated - - -class Hero(SQLModel, table=True): - id: Union[int, None] = Field(default=None, primary_key=True) - name: str = Field(index=True) - age: Union[int, None] = Field(default=None, index=True) - secret_name: str - - -sqlite_file_name = "database.db" -sqlite_url = f"sqlite:///{sqlite_file_name}" - -connect_args = {"check_same_thread": False} -engine = create_engine(sqlite_url, connect_args=connect_args) - - -def create_db_and_tables(): - SQLModel.metadata.create_all(engine) - - -def get_session(): - with Session(engine) as session: - yield session - - -SessionDep = Annotated[Session, Depends(get_session)] - -app = FastAPI() - - -@app.on_event("startup") -def on_startup(): - create_db_and_tables() - - -@app.post("/heroes/") -def create_hero(hero: Hero, session: SessionDep) -> Hero: - session.add(hero) - session.commit() - session.refresh(hero) - return hero - - -@app.get("/heroes/") -def read_heroes( - session: SessionDep, - offset: int = 0, - limit: Annotated[int, Query(le=100)] = 100, -) -> List[Hero]: - heroes = session.exec(select(Hero).offset(offset).limit(limit)).all() - return heroes - - -@app.get("/heroes/{hero_id}") -def read_hero(hero_id: int, session: SessionDep) -> Hero: - hero = session.get(Hero, hero_id) - if not hero: - raise HTTPException(status_code=404, detail="Hero not found") - return hero - - -@app.delete("/heroes/{hero_id}") -def delete_hero(hero_id: int, session: SessionDep): - hero = session.get(Hero, hero_id) - if not hero: - raise HTTPException(status_code=404, detail="Hero not found") - session.delete(hero) - session.commit() - return {"ok": True} diff --git a/docs_src/sql_databases/tutorial002.py b/docs_src/sql_databases/tutorial002.py deleted file mode 100644 index 4350d19c61..0000000000 --- a/docs_src/sql_databases/tutorial002.py +++ /dev/null @@ -1,104 +0,0 @@ -from typing import List, Union - -from fastapi import Depends, FastAPI, HTTPException, Query -from sqlmodel import Field, Session, SQLModel, create_engine, select - - -class HeroBase(SQLModel): - name: str = Field(index=True) - age: Union[int, None] = Field(default=None, index=True) - - -class Hero(HeroBase, table=True): - id: Union[int, None] = Field(default=None, primary_key=True) - secret_name: str - - -class HeroPublic(HeroBase): - id: int - - -class HeroCreate(HeroBase): - secret_name: str - - -class HeroUpdate(HeroBase): - name: Union[str, None] = None - age: Union[int, None] = None - secret_name: Union[str, None] = None - - -sqlite_file_name = "database.db" -sqlite_url = f"sqlite:///{sqlite_file_name}" - -connect_args = {"check_same_thread": False} -engine = create_engine(sqlite_url, connect_args=connect_args) - - -def create_db_and_tables(): - SQLModel.metadata.create_all(engine) - - -def get_session(): - with Session(engine) as session: - yield session - - -app = FastAPI() - - -@app.on_event("startup") -def on_startup(): - create_db_and_tables() - - -@app.post("/heroes/", response_model=HeroPublic) -def create_hero(hero: HeroCreate, session: Session = Depends(get_session)): - db_hero = Hero.model_validate(hero) - session.add(db_hero) - session.commit() - session.refresh(db_hero) - return db_hero - - -@app.get("/heroes/", response_model=List[HeroPublic]) -def read_heroes( - session: Session = Depends(get_session), - offset: int = 0, - limit: int = Query(default=100, le=100), -): - heroes = session.exec(select(Hero).offset(offset).limit(limit)).all() - return heroes - - -@app.get("/heroes/{hero_id}", response_model=HeroPublic) -def read_hero(hero_id: int, session: Session = Depends(get_session)): - hero = session.get(Hero, hero_id) - if not hero: - raise HTTPException(status_code=404, detail="Hero not found") - return hero - - -@app.patch("/heroes/{hero_id}", response_model=HeroPublic) -def update_hero( - hero_id: int, hero: HeroUpdate, session: Session = Depends(get_session) -): - hero_db = session.get(Hero, hero_id) - if not hero_db: - raise HTTPException(status_code=404, detail="Hero not found") - hero_data = hero.model_dump(exclude_unset=True) - hero_db.sqlmodel_update(hero_data) - session.add(hero_db) - session.commit() - session.refresh(hero_db) - return hero_db - - -@app.delete("/heroes/{hero_id}") -def delete_hero(hero_id: int, session: Session = Depends(get_session)): - hero = session.get(Hero, hero_id) - if not hero: - raise HTTPException(status_code=404, detail="Hero not found") - session.delete(hero) - session.commit() - return {"ok": True} diff --git a/docs_src/sql_databases/tutorial002_an.py b/docs_src/sql_databases/tutorial002_an.py deleted file mode 100644 index 15e3d7c3a5..0000000000 --- a/docs_src/sql_databases/tutorial002_an.py +++ /dev/null @@ -1,104 +0,0 @@ -from typing import List, Union - -from fastapi import Depends, FastAPI, HTTPException, Query -from sqlmodel import Field, Session, SQLModel, create_engine, select -from typing_extensions import Annotated - - -class HeroBase(SQLModel): - name: str = Field(index=True) - age: Union[int, None] = Field(default=None, index=True) - - -class Hero(HeroBase, table=True): - id: Union[int, None] = Field(default=None, primary_key=True) - secret_name: str - - -class HeroPublic(HeroBase): - id: int - - -class HeroCreate(HeroBase): - secret_name: str - - -class HeroUpdate(HeroBase): - name: Union[str, None] = None - age: Union[int, None] = None - secret_name: Union[str, None] = None - - -sqlite_file_name = "database.db" -sqlite_url = f"sqlite:///{sqlite_file_name}" - -connect_args = {"check_same_thread": False} -engine = create_engine(sqlite_url, connect_args=connect_args) - - -def create_db_and_tables(): - SQLModel.metadata.create_all(engine) - - -def get_session(): - with Session(engine) as session: - yield session - - -SessionDep = Annotated[Session, Depends(get_session)] -app = FastAPI() - - -@app.on_event("startup") -def on_startup(): - create_db_and_tables() - - -@app.post("/heroes/", response_model=HeroPublic) -def create_hero(hero: HeroCreate, session: SessionDep): - db_hero = Hero.model_validate(hero) - session.add(db_hero) - session.commit() - session.refresh(db_hero) - return db_hero - - -@app.get("/heroes/", response_model=List[HeroPublic]) -def read_heroes( - session: SessionDep, - offset: int = 0, - limit: Annotated[int, Query(le=100)] = 100, -): - heroes = session.exec(select(Hero).offset(offset).limit(limit)).all() - return heroes - - -@app.get("/heroes/{hero_id}", response_model=HeroPublic) -def read_hero(hero_id: int, session: SessionDep): - hero = session.get(Hero, hero_id) - if not hero: - raise HTTPException(status_code=404, detail="Hero not found") - return hero - - -@app.patch("/heroes/{hero_id}", response_model=HeroPublic) -def update_hero(hero_id: int, hero: HeroUpdate, session: SessionDep): - hero_db = session.get(Hero, hero_id) - if not hero_db: - raise HTTPException(status_code=404, detail="Hero not found") - hero_data = hero.model_dump(exclude_unset=True) - hero_db.sqlmodel_update(hero_data) - session.add(hero_db) - session.commit() - session.refresh(hero_db) - return hero_db - - -@app.delete("/heroes/{hero_id}") -def delete_hero(hero_id: int, session: SessionDep): - hero = session.get(Hero, hero_id) - if not hero: - raise HTTPException(status_code=404, detail="Hero not found") - session.delete(hero) - session.commit() - return {"ok": True} diff --git a/docs_src/static_files/tutorial001.py b/docs_src/static_files/tutorial001_py39.py similarity index 100% rename from docs_src/static_files/tutorial001.py rename to docs_src/static_files/tutorial001_py39.py diff --git a/docs_src/sub_applications/tutorial001.py b/docs_src/sub_applications/tutorial001_py39.py similarity index 100% rename from docs_src/sub_applications/tutorial001.py rename to docs_src/sub_applications/tutorial001_py39.py diff --git a/docs_src/templates/tutorial001.py b/docs_src/templates/tutorial001_py39.py similarity index 100% rename from docs_src/templates/tutorial001.py rename to docs_src/templates/tutorial001_py39.py diff --git a/docs_src/using_request_directly/tutorial001.py b/docs_src/using_request_directly/tutorial001_py39.py similarity index 100% rename from docs_src/using_request_directly/tutorial001.py rename to docs_src/using_request_directly/tutorial001_py39.py diff --git a/docs_src/websockets/tutorial001.py b/docs_src/websockets/tutorial001_py39.py similarity index 100% rename from docs_src/websockets/tutorial001.py rename to docs_src/websockets/tutorial001_py39.py diff --git a/docs_src/websockets/tutorial002_an.py b/docs_src/websockets/tutorial002_an.py deleted file mode 100644 index c838fbd306..0000000000 --- a/docs_src/websockets/tutorial002_an.py +++ /dev/null @@ -1,93 +0,0 @@ -from typing import Union - -from fastapi import ( - Cookie, - Depends, - FastAPI, - Query, - WebSocket, - WebSocketException, - status, -) -from fastapi.responses import HTMLResponse -from typing_extensions import Annotated - -app = FastAPI() - -html = """ - - - - Chat - - -

WebSocket Chat

-
- - - -
- - -
- - - - -""" - - -@app.get("/") -async def get(): - return HTMLResponse(html) - - -async def get_cookie_or_token( - websocket: WebSocket, - session: Annotated[Union[str, None], Cookie()] = None, - token: Annotated[Union[str, None], Query()] = None, -): - if session is None and token is None: - raise WebSocketException(code=status.WS_1008_POLICY_VIOLATION) - return session or token - - -@app.websocket("/items/{item_id}/ws") -async def websocket_endpoint( - *, - websocket: WebSocket, - item_id: str, - q: Union[int, None] = None, - cookie_or_token: Annotated[str, Depends(get_cookie_or_token)], -): - await websocket.accept() - while True: - data = await websocket.receive_text() - await websocket.send_text( - f"Session cookie or query token value is: {cookie_or_token}" - ) - if q is not None: - await websocket.send_text(f"Query parameter q is: {q}") - await websocket.send_text(f"Message text was: {data}, for item ID: {item_id}") diff --git a/docs_src/websockets/tutorial002.py b/docs_src/websockets/tutorial002_py39.py similarity index 100% rename from docs_src/websockets/tutorial002.py rename to docs_src/websockets/tutorial002_py39.py diff --git a/docs_src/websockets/tutorial003.py b/docs_src/websockets/tutorial003.py deleted file mode 100644 index d561633a8d..0000000000 --- a/docs_src/websockets/tutorial003.py +++ /dev/null @@ -1,83 +0,0 @@ -from typing import List - -from fastapi import FastAPI, WebSocket, WebSocketDisconnect -from fastapi.responses import HTMLResponse - -app = FastAPI() - -html = """ - - - - Chat - - -

WebSocket Chat

-

Your ID:

-
- - -
- - - - -""" - - -class ConnectionManager: - def __init__(self): - self.active_connections: List[WebSocket] = [] - - async def connect(self, websocket: WebSocket): - await websocket.accept() - self.active_connections.append(websocket) - - def disconnect(self, websocket: WebSocket): - self.active_connections.remove(websocket) - - async def send_personal_message(self, message: str, websocket: WebSocket): - await websocket.send_text(message) - - async def broadcast(self, message: str): - for connection in self.active_connections: - await connection.send_text(message) - - -manager = ConnectionManager() - - -@app.get("/") -async def get(): - return HTMLResponse(html) - - -@app.websocket("/ws/{client_id}") -async def websocket_endpoint(websocket: WebSocket, client_id: int): - await manager.connect(websocket) - try: - while True: - data = await websocket.receive_text() - await manager.send_personal_message(f"You wrote: {data}", websocket) - await manager.broadcast(f"Client #{client_id} says: {data}") - except WebSocketDisconnect: - manager.disconnect(websocket) - await manager.broadcast(f"Client #{client_id} left the chat") diff --git a/docs_src/wsgi/tutorial001.py b/docs_src/wsgi/tutorial001_py39.py similarity index 100% rename from docs_src/wsgi/tutorial001.py rename to docs_src/wsgi/tutorial001_py39.py diff --git a/fastapi/__init__.py b/fastapi/__init__.py index e02969c55f..2f13448467 100644 --- a/fastapi/__init__.py +++ b/fastapi/__init__.py @@ -1,6 +1,6 @@ """FastAPI framework, high performance, easy to learn, fast to code, ready for production""" -__version__ = "0.124.4" +__version__ = "0.125.0" from starlette import status as status diff --git a/fastapi/_compat/main.py b/fastapi/_compat/main.py index e5275950e8..2043a66781 100644 --- a/fastapi/_compat/main.py +++ b/fastapi/_compat/main.py @@ -1,12 +1,8 @@ import sys +from collections.abc import Sequence from functools import lru_cache from typing import ( Any, - Dict, - List, - Sequence, - Tuple, - Type, ) from fastapi._compat import may_v1 @@ -50,7 +46,7 @@ else: @lru_cache -def get_cached_model_fields(model: Type[BaseModel]) -> List[ModelField]: +def get_cached_model_fields(model: type[BaseModel]) -> list[ModelField]: if lenient_issubclass(model, may_v1.BaseModel): from fastapi._compat import v1 @@ -119,7 +115,7 @@ def copy_field_info(*, field_info: FieldInfo, annotation: Any) -> FieldInfo: def create_body_model( *, fields: Sequence[ModelField], model_name: str -) -> Type[BaseModel]: +) -> type[BaseModel]: if fields and isinstance(fields[0], may_v1.ModelField): from fastapi._compat import v1 @@ -221,7 +217,7 @@ def serialize_sequence_value(*, field: ModelField, value: Any) -> Sequence[Any]: return v2.serialize_sequence_value(field=field, value=value) # type: ignore[arg-type] -def _model_rebuild(model: Type[BaseModel]) -> None: +def _model_rebuild(model: type[BaseModel]) -> None: if lenient_issubclass(model, may_v1.BaseModel): from fastapi._compat import v1 @@ -232,7 +228,7 @@ def _model_rebuild(model: Type[BaseModel]) -> None: v2._model_rebuild(model) -def get_compat_model_name_map(fields: List[ModelField]) -> ModelNameMap: +def get_compat_model_name_map(fields: list[ModelField]) -> ModelNameMap: v1_model_fields = [ field for field in fields if isinstance(field, may_v1.ModelField) ] @@ -266,15 +262,15 @@ def get_compat_model_name_map(fields: List[ModelField]) -> ModelNameMap: def get_definitions( *, - fields: List[ModelField], + fields: list[ModelField], model_name_map: ModelNameMap, separate_input_output_schemas: bool = True, -) -> Tuple[ - Dict[ - Tuple[ModelField, Literal["validation", "serialization"]], +) -> tuple[ + dict[ + tuple[ModelField, Literal["validation", "serialization"]], may_v1.JsonSchemaValue, ], - Dict[str, Dict[str, Any]], + dict[str, dict[str, Any]], ]: if sys.version_info < (3, 14): v1_fields = [field for field in fields if isinstance(field, may_v1.ModelField)] @@ -315,12 +311,12 @@ def get_schema_from_model_field( *, field: ModelField, model_name_map: ModelNameMap, - field_mapping: Dict[ - Tuple[ModelField, Literal["validation", "serialization"]], + field_mapping: dict[ + tuple[ModelField, Literal["validation", "serialization"]], may_v1.JsonSchemaValue, ], separate_input_output_schemas: bool = True, -) -> Dict[str, Any]: +) -> dict[str, Any]: if isinstance(field, may_v1.ModelField): from fastapi._compat import v1 diff --git a/fastapi/_compat/may_v1.py b/fastapi/_compat/may_v1.py index beea4d167f..c772162283 100644 --- a/fastapi/_compat/may_v1.py +++ b/fastapi/_compat/may_v1.py @@ -1,5 +1,6 @@ import sys -from typing import Any, Dict, List, Literal, Sequence, Tuple, Type, Union +from collections.abc import Sequence +from typing import Any, Literal, Union from fastapi.types import ModelNameMap @@ -60,14 +61,14 @@ if sys.version_info >= (3, 14): def get_definitions( *, - fields: List[ModelField], + fields: list[ModelField], model_name_map: ModelNameMap, separate_input_output_schemas: bool = True, - ) -> Tuple[ - Dict[ - Tuple[ModelField, Literal["validation", "serialization"]], JsonSchemaValue + ) -> tuple[ + dict[ + tuple[ModelField, Literal["validation", "serialization"]], JsonSchemaValue ], - Dict[str, Dict[str, Any]], + dict[str, dict[str, Any]], ]: return {}, {} # pragma: no cover @@ -94,11 +95,11 @@ else: from .v1 import get_definitions as get_definitions -RequestErrorModel: Type[BaseModel] = create_model("Request") +RequestErrorModel: type[BaseModel] = create_model("Request") -def _normalize_errors(errors: Sequence[Any]) -> List[Dict[str, Any]]: - use_errors: List[Any] = [] +def _normalize_errors(errors: Sequence[Any]) -> list[dict[str, Any]]: + use_errors: list[Any] = [] for error in errors: if isinstance(error, ErrorWrapper): new_errors = ValidationError( # type: ignore[call-arg] @@ -113,9 +114,9 @@ def _normalize_errors(errors: Sequence[Any]) -> List[Dict[str, Any]]: def _regenerate_error_with_loc( - *, errors: Sequence[Any], loc_prefix: Tuple[Union[str, int], ...] -) -> List[Dict[str, Any]]: - updated_loc_errors: List[Any] = [ + *, errors: Sequence[Any], loc_prefix: tuple[Union[str, int], ...] +) -> list[dict[str, Any]]: + updated_loc_errors: list[Any] = [ {**err, "loc": loc_prefix + err.get("loc", ())} for err in _normalize_errors(errors) ] diff --git a/fastapi/_compat/model_field.py b/fastapi/_compat/model_field.py index fa2008c5e0..47d05cb946 100644 --- a/fastapi/_compat/model_field.py +++ b/fastapi/_compat/model_field.py @@ -1,8 +1,5 @@ from typing import ( Any, - Dict, - List, - Tuple, Union, ) @@ -34,10 +31,10 @@ class ModelField(Protocol): def validate( self, value: Any, - values: Dict[str, Any] = {}, # noqa: B006 + values: dict[str, Any] = {}, # noqa: B006 *, - loc: Tuple[Union[int, str], ...] = (), - ) -> Tuple[Any, Union[List[Dict[str, Any]], None]]: ... + loc: tuple[Union[int, str], ...] = (), + ) -> tuple[Any, Union[list[dict[str, Any]], None]]: ... def serialize( self, diff --git a/fastapi/_compat/shared.py b/fastapi/_compat/shared.py index cabf482283..3a11e88ac9 100644 --- a/fastapi/_compat/shared.py +++ b/fastapi/_compat/shared.py @@ -2,17 +2,11 @@ import sys import types import typing from collections import deque +from collections.abc import Mapping, Sequence from dataclasses import is_dataclass from typing import ( + Annotated, Any, - Deque, - FrozenSet, - List, - Mapping, - Sequence, - Set, - Tuple, - Type, Union, ) @@ -21,16 +15,10 @@ from fastapi.types import UnionType from pydantic import BaseModel from pydantic.version import VERSION as PYDANTIC_VERSION from starlette.datastructures import UploadFile -from typing_extensions import Annotated, get_args, get_origin +from typing_extensions import get_args, get_origin # Copy from Pydantic v2, compatible with v1 -if sys.version_info < (3, 9): - # Pydantic no longer supports Python 3.8, this might be incorrect, but the code - # this is used for is also never reached in this codebase, as it's a copy of - # Pydantic's lenient_issubclass, just for compatibility with v1 - # TODO: remove when dropping support for Python 3.8 - WithArgsTypes: Tuple[Any, ...] = () -elif sys.version_info < (3, 10): +if sys.version_info < (3, 10): WithArgsTypes: tuple[Any, ...] = (typing._GenericAlias, types.GenericAlias) # type: ignore[attr-defined] else: WithArgsTypes: tuple[Any, ...] = ( @@ -45,26 +33,21 @@ PYDANTIC_V2 = PYDANTIC_VERSION_MINOR_TUPLE[0] == 2 sequence_annotation_to_type = { Sequence: list, - List: list, list: list, - Tuple: tuple, tuple: tuple, - Set: set, set: set, - FrozenSet: frozenset, frozenset: frozenset, - Deque: deque, deque: deque, } sequence_types = tuple(sequence_annotation_to_type.keys()) -Url: Type[Any] +Url: type[Any] # Copy of Pydantic v2, compatible with v1 def lenient_issubclass( - cls: Any, class_or_tuple: Union[Type[Any], Tuple[Type[Any], ...], None] + cls: Any, class_or_tuple: Union[type[Any], tuple[type[Any], ...], None] ) -> bool: try: return isinstance(cls, type) and issubclass(cls, class_or_tuple) # type: ignore[arg-type] @@ -74,13 +57,13 @@ def lenient_issubclass( raise # pragma: no cover -def _annotation_is_sequence(annotation: Union[Type[Any], None]) -> bool: +def _annotation_is_sequence(annotation: Union[type[Any], None]) -> bool: if lenient_issubclass(annotation, (str, bytes)): return False - return lenient_issubclass(annotation, sequence_types) # type: ignore[arg-type] + return lenient_issubclass(annotation, sequence_types) -def field_annotation_is_sequence(annotation: Union[Type[Any], None]) -> bool: +def field_annotation_is_sequence(annotation: Union[type[Any], None]) -> bool: origin = get_origin(annotation) if origin is Union or origin is UnionType: for arg in get_args(annotation): @@ -93,10 +76,10 @@ def field_annotation_is_sequence(annotation: Union[Type[Any], None]) -> bool: def value_is_sequence(value: Any) -> bool: - return isinstance(value, sequence_types) and not isinstance(value, (str, bytes)) # type: ignore[arg-type] + return isinstance(value, sequence_types) and not isinstance(value, (str, bytes)) -def _annotation_is_complex(annotation: Union[Type[Any], None]) -> bool: +def _annotation_is_complex(annotation: Union[type[Any], None]) -> bool: return ( lenient_issubclass( annotation, (BaseModel, may_v1.BaseModel, Mapping, UploadFile) @@ -106,7 +89,7 @@ def _annotation_is_complex(annotation: Union[Type[Any], None]) -> bool: ) -def field_annotation_is_complex(annotation: Union[Type[Any], None]) -> bool: +def field_annotation_is_complex(annotation: Union[type[Any], None]) -> bool: origin = get_origin(annotation) if origin is Union or origin is UnionType: return any(field_annotation_is_complex(arg) for arg in get_args(annotation)) @@ -127,7 +110,7 @@ def field_annotation_is_scalar(annotation: Any) -> bool: return annotation is Ellipsis or not field_annotation_is_complex(annotation) -def field_annotation_is_scalar_sequence(annotation: Union[Type[Any], None]) -> bool: +def field_annotation_is_scalar_sequence(annotation: Union[type[Any], None]) -> bool: origin = get_origin(annotation) if origin is Union or origin is UnionType: at_least_one_scalar_sequence = False diff --git a/fastapi/_compat/v1.py b/fastapi/_compat/v1.py index e17ce8beaf..b29a61f734 100644 --- a/fastapi/_compat/v1.py +++ b/fastapi/_compat/v1.py @@ -1,15 +1,10 @@ +from collections.abc import Sequence from copy import copy from dataclasses import dataclass, is_dataclass from enum import Enum from typing import ( Any, Callable, - Dict, - List, - Sequence, - Set, - Tuple, - Type, Union, ) @@ -124,7 +119,7 @@ else: GetJsonSchemaHandler = Any -JsonSchemaValue = Dict[str, Any] +JsonSchemaValue = dict[str, Any] CoreSchema = Any Url = AnyUrl @@ -154,7 +149,7 @@ class PydanticSchemaGenerationError(Exception): pass -RequestErrorModel: Type[BaseModel] = create_model("Request") +RequestErrorModel: type[BaseModel] = create_model("Request") def with_info_plain_validator_function( @@ -169,10 +164,10 @@ def with_info_plain_validator_function( def get_model_definitions( *, - flat_models: Set[Union[Type[BaseModel], Type[Enum]]], - model_name_map: Dict[Union[Type[BaseModel], Type[Enum]], str], -) -> Dict[str, Any]: - definitions: Dict[str, Dict[str, Any]] = {} + flat_models: set[Union[type[BaseModel], type[Enum]]], + model_name_map: dict[Union[type[BaseModel], type[Enum]], str], +) -> dict[str, Any]: + definitions: dict[str, dict[str, Any]] = {} for model in flat_models: m_schema, m_definitions, m_nested_models = model_process_schema( model, model_name_map=model_name_map, ref_prefix=REF_PREFIX @@ -219,7 +214,7 @@ def is_pv1_scalar_sequence_field(field: ModelField) -> bool: return False -def _model_rebuild(model: Type[BaseModel]) -> None: +def _model_rebuild(model: type[BaseModel]) -> None: model.update_forward_refs() @@ -237,11 +232,11 @@ def get_schema_from_model_field( *, field: ModelField, model_name_map: ModelNameMap, - field_mapping: Dict[ - Tuple[ModelField, Literal["validation", "serialization"]], JsonSchemaValue + field_mapping: dict[ + tuple[ModelField, Literal["validation", "serialization"]], JsonSchemaValue ], separate_input_output_schemas: bool = True, -) -> Dict[str, Any]: +) -> dict[str, Any]: return field_schema( # type: ignore[no-any-return] field, model_name_map=model_name_map, ref_prefix=REF_PREFIX )[0] @@ -254,12 +249,12 @@ def get_schema_from_model_field( def get_definitions( *, - fields: List[ModelField], + fields: list[ModelField], model_name_map: ModelNameMap, separate_input_output_schemas: bool = True, -) -> Tuple[ - Dict[Tuple[ModelField, Literal["validation", "serialization"]], JsonSchemaValue], - Dict[str, Dict[str, Any]], +) -> tuple[ + dict[tuple[ModelField, Literal["validation", "serialization"]], JsonSchemaValue], + dict[str, dict[str, Any]], ]: models = get_flat_models_from_fields(fields, known_models=set()) return {}, get_model_definitions(flat_models=models, model_name_map=model_name_map) @@ -293,7 +288,7 @@ def serialize_sequence_value(*, field: ModelField, value: Any) -> Sequence[Any]: return sequence_shape_to_type[field.shape](value) # type: ignore[no-any-return] -def get_missing_field_error(loc: Tuple[str, ...]) -> Dict[str, Any]: +def get_missing_field_error(loc: tuple[str, ...]) -> dict[str, Any]: missing_field_error = ErrorWrapper(MissingError(), loc=loc) new_error = ValidationError([missing_field_error], RequestErrorModel) return new_error.errors()[0] # type: ignore[return-value] @@ -301,12 +296,12 @@ def get_missing_field_error(loc: Tuple[str, ...]) -> Dict[str, Any]: def create_body_model( *, fields: Sequence[ModelField], model_name: str -) -> Type[BaseModel]: +) -> type[BaseModel]: BodyModel = create_model(model_name) for f in fields: BodyModel.__fields__[f.name] = f # type: ignore[index] return BodyModel -def get_model_fields(model: Type[BaseModel]) -> List[ModelField]: +def get_model_fields(model: type[BaseModel]) -> list[ModelField]: return list(model.__fields__.values()) # type: ignore[attr-defined] diff --git a/fastapi/_compat/v2.py b/fastapi/_compat/v2.py index a17d625568..c4fa49e403 100644 --- a/fastapi/_compat/v2.py +++ b/fastapi/_compat/v2.py @@ -1,16 +1,12 @@ import re import warnings +from collections.abc import Sequence from copy import copy, deepcopy from dataclasses import dataclass, is_dataclass from enum import Enum from typing import ( + Annotated, Any, - Dict, - List, - Sequence, - Set, - Tuple, - Type, Union, cast, ) @@ -33,7 +29,7 @@ from pydantic.json_schema import JsonSchemaValue as JsonSchemaValue from pydantic_core import CoreSchema as CoreSchema from pydantic_core import PydanticUndefined, PydanticUndefinedType from pydantic_core import Url as Url -from typing_extensions import Annotated, Literal, get_args, get_origin +from typing_extensions import Literal, get_args, get_origin try: from pydantic_core.core_schema import ( @@ -77,7 +73,7 @@ _Attrs = { # TODO: remove when dropping support for Pydantic < v2.12.3 -def asdict(field_info: FieldInfo) -> Dict[str, Any]: +def asdict(field_info: FieldInfo) -> dict[str, Any]: attributes = {} for attr in _Attrs: value = getattr(field_info, attr, Undefined) @@ -169,10 +165,10 @@ class ModelField: def validate( self, value: Any, - values: Dict[str, Any] = {}, # noqa: B006 + values: dict[str, Any] = {}, # noqa: B006 *, - loc: Tuple[Union[int, str], ...] = (), - ) -> Tuple[Any, Union[List[Dict[str, Any]], None]]: + loc: tuple[Union[int, str], ...] = (), + ) -> tuple[Any, Union[list[dict[str, Any]], None]]: try: return ( self._type_adapter.validate_python(value, from_attributes=True), @@ -220,7 +216,7 @@ def get_annotation_from_field_info( return annotation -def _model_rebuild(model: Type[BaseModel]) -> None: +def _model_rebuild(model: type[BaseModel]) -> None: model.model_rebuild() @@ -245,11 +241,11 @@ def get_schema_from_model_field( *, field: ModelField, model_name_map: ModelNameMap, - field_mapping: Dict[ - Tuple[ModelField, Literal["validation", "serialization"]], JsonSchemaValue + field_mapping: dict[ + tuple[ModelField, Literal["validation", "serialization"]], JsonSchemaValue ], separate_input_output_schemas: bool = True, -) -> Dict[str, Any]: +) -> dict[str, Any]: override_mode: Union[Literal["validation"], None] = ( None if (separate_input_output_schemas or _has_computed_fields(field)) @@ -277,9 +273,9 @@ def get_definitions( fields: Sequence[ModelField], model_name_map: ModelNameMap, separate_input_output_schemas: bool = True, -) -> Tuple[ - Dict[Tuple[ModelField, Literal["validation", "serialization"]], JsonSchemaValue], - Dict[str, Dict[str, Any]], +) -> tuple[ + dict[tuple[ModelField, Literal["validation", "serialization"]], JsonSchemaValue], + dict[str, dict[str, Any]], ]: schema_generator = GenerateJsonSchema(ref_template=REF_TEMPLATE) validation_fields = [field for field in fields if field.mode == "validation"] @@ -324,7 +320,7 @@ def get_definitions( for field in list(fields) + list(unique_flat_model_fields) ] field_mapping, definitions = schema_generator.generate_definitions(inputs=inputs) - for item_def in cast(Dict[str, Dict[str, Any]], definitions).values(): + for item_def in cast(dict[str, dict[str, Any]], definitions).values(): if "description" in item_def: item_description = cast(str, item_def["description"]).split("\f")[0] item_def["description"] = item_description @@ -338,9 +334,9 @@ def get_definitions( def _replace_refs( *, - schema: Dict[str, Any], - old_name_to_new_name_map: Dict[str, str], -) -> Dict[str, Any]: + schema: dict[str, Any], + old_name_to_new_name_map: dict[str, str], +) -> dict[str, Any]: new_schema = deepcopy(schema) for key, value in new_schema.items(): if key == "$ref": @@ -375,13 +371,13 @@ def _replace_refs( def _remap_definitions_and_field_mappings( *, model_name_map: ModelNameMap, - definitions: Dict[str, Any], - field_mapping: Dict[ - Tuple[ModelField, Literal["validation", "serialization"]], JsonSchemaValue + definitions: dict[str, Any], + field_mapping: dict[ + tuple[ModelField, Literal["validation", "serialization"]], JsonSchemaValue ], -) -> Tuple[ - Dict[Tuple[ModelField, Literal["validation", "serialization"]], JsonSchemaValue], - Dict[str, Any], +) -> tuple[ + dict[tuple[ModelField, Literal["validation", "serialization"]], JsonSchemaValue], + dict[str, Any], ]: old_name_to_new_name_map = {} for field_key, schema in field_mapping.items(): @@ -394,8 +390,8 @@ def _remap_definitions_and_field_mappings( continue old_name_to_new_name_map[old_name] = new_name - new_field_mapping: Dict[ - Tuple[ModelField, Literal["validation", "serialization"]], JsonSchemaValue + new_field_mapping: dict[ + tuple[ModelField, Literal["validation", "serialization"]], JsonSchemaValue ] = {} for field_key, schema in field_mapping.items(): new_schema = _replace_refs( @@ -461,10 +457,10 @@ def serialize_sequence_value(*, field: ModelField, value: Any) -> Sequence[Any]: origin_type = get_origin(union_arg) or union_arg break assert issubclass(origin_type, shared.sequence_types) # type: ignore[arg-type] - return shared.sequence_annotation_to_type[origin_type](value) # type: ignore[no-any-return] + return shared.sequence_annotation_to_type[origin_type](value) # type: ignore[no-any-return,index] -def get_missing_field_error(loc: Tuple[str, ...]) -> Dict[str, Any]: +def get_missing_field_error(loc: tuple[str, ...]) -> dict[str, Any]: error = ValidationError.from_exception_data( "Field required", [{"type": "missing", "loc": loc, "input": {}}] ).errors(include_url=False)[0] @@ -474,14 +470,14 @@ def get_missing_field_error(loc: Tuple[str, ...]) -> Dict[str, Any]: def create_body_model( *, fields: Sequence[ModelField], model_name: str -) -> Type[BaseModel]: +) -> type[BaseModel]: field_params = {f.name: (f.field_info.annotation, f.field_info) for f in fields} - BodyModel: Type[BaseModel] = create_model(model_name, **field_params) # type: ignore[call-overload] + BodyModel: type[BaseModel] = create_model(model_name, **field_params) # type: ignore[call-overload] return BodyModel -def get_model_fields(model: Type[BaseModel]) -> List[ModelField]: - model_fields: List[ModelField] = [] +def get_model_fields(model: type[BaseModel]) -> list[ModelField]: + model_fields: list[ModelField] = [] for name, field_info in model.model_fields.items(): type_ = field_info.annotation if lenient_issubclass(type_, (BaseModel, dict)) or is_dataclass(type_): @@ -501,17 +497,17 @@ def get_model_fields(model: Type[BaseModel]) -> List[ModelField]: # Duplicate of several schema functions from Pydantic v1 to make them compatible with # Pydantic v2 and allow mixing the models -TypeModelOrEnum = Union[Type["BaseModel"], Type[Enum]] -TypeModelSet = Set[TypeModelOrEnum] +TypeModelOrEnum = Union[type["BaseModel"], type[Enum]] +TypeModelSet = set[TypeModelOrEnum] def normalize_name(name: str) -> str: return re.sub(r"[^a-zA-Z0-9.\-_]", "_", name) -def get_model_name_map(unique_models: TypeModelSet) -> Dict[TypeModelOrEnum, str]: +def get_model_name_map(unique_models: TypeModelSet) -> dict[TypeModelOrEnum, str]: name_model_map = {} - conflicting_names: Set[str] = set() + conflicting_names: set[str] = set() for model in unique_models: model_name = normalize_name(model.__name__) if model_name in conflicting_names: @@ -528,7 +524,7 @@ def get_model_name_map(unique_models: TypeModelSet) -> Dict[TypeModelOrEnum, str def get_flat_models_from_model( - model: Type["BaseModel"], known_models: Union[TypeModelSet, None] = None + model: type["BaseModel"], known_models: Union[TypeModelSet, None] = None ) -> TypeModelSet: known_models = known_models or set() fields = get_model_fields(model) diff --git a/fastapi/applications.py b/fastapi/applications.py index 02193312b9..54175cb3b0 100644 --- a/fastapi/applications.py +++ b/fastapi/applications.py @@ -1,14 +1,10 @@ +from collections.abc import Awaitable, Coroutine, Sequence from enum import Enum from typing import ( + Annotated, Any, - Awaitable, Callable, - Coroutine, - Dict, - List, Optional, - Sequence, - Type, TypeVar, Union, ) @@ -44,7 +40,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, deprecated +from typing_extensions import deprecated AppType = TypeVar("AppType", bound="FastAPI") @@ -81,7 +77,7 @@ class FastAPI(Starlette): ), ] = False, routes: Annotated[ - Optional[List[BaseRoute]], + Optional[list[BaseRoute]], Doc( """ **Note**: you probably shouldn't use this parameter, it is inherited @@ -230,7 +226,7 @@ class FastAPI(Starlette): ), ] = "/openapi.json", openapi_tags: Annotated[ - Optional[List[Dict[str, Any]]], + Optional[list[dict[str, Any]]], Doc( """ A list of tags used by OpenAPI, these are the same `tags` you can set @@ -290,7 +286,7 @@ class FastAPI(Starlette): ), ] = None, servers: Annotated[ - Optional[List[Dict[str, Union[str, Any]]]], + Optional[list[dict[str, Union[str, Any]]]], Doc( """ A `list` of `dict`s with connectivity information to a target server. @@ -361,7 +357,7 @@ class FastAPI(Starlette): ), ] = None, default_response_class: Annotated[ - Type[Response], + type[Response], Doc( """ The default response class to be used. @@ -467,7 +463,7 @@ class FastAPI(Starlette): ), ] = "/docs/oauth2-redirect", swagger_ui_init_oauth: Annotated[ - Optional[Dict[str, Any]], + Optional[dict[str, Any]], Doc( """ OAuth2 configuration for the Swagger UI, by default shown at `/docs`. @@ -493,8 +489,8 @@ class FastAPI(Starlette): ] = None, exception_handlers: Annotated[ Optional[ - Dict[ - Union[int, Type[Exception]], + dict[ + Union[int, type[Exception]], Callable[[Request, Any], Coroutine[Any, Any, Response]], ] ], @@ -567,7 +563,7 @@ class FastAPI(Starlette): ), ] = None, contact: Annotated[ - Optional[Dict[str, Union[str, Any]]], + Optional[dict[str, Union[str, Any]]], Doc( """ A dictionary with the contact information for the exposed API. @@ -600,7 +596,7 @@ class FastAPI(Starlette): ), ] = None, license_info: Annotated[ - Optional[Dict[str, Union[str, Any]]], + Optional[dict[str, Union[str, Any]]], Doc( """ A dictionary with the license information for the exposed API. @@ -689,7 +685,7 @@ class FastAPI(Starlette): ), ] = True, responses: Annotated[ - Optional[Dict[Union[int, str], Dict[str, Any]]], + Optional[dict[Union[int, str], dict[str, Any]]], Doc( """ Additional responses to be shown in OpenAPI. @@ -705,7 +701,7 @@ class FastAPI(Starlette): ), ] = None, callbacks: Annotated[ - Optional[List[BaseRoute]], + Optional[list[BaseRoute]], Doc( """ OpenAPI callbacks that should apply to all *path operations*. @@ -762,7 +758,7 @@ class FastAPI(Starlette): ), ] = True, swagger_ui_parameters: Annotated[ - Optional[Dict[str, Any]], + Optional[dict[str, Any]], Doc( """ Parameters to configure Swagger UI, the autogenerated interactive API @@ -820,7 +816,7 @@ class FastAPI(Starlette): ), ] = True, openapi_external_docs: Annotated[ - Optional[Dict[str, Any]], + Optional[dict[str, Any]], Doc( """ This field allows you to provide additional external documentation links. @@ -906,7 +902,7 @@ class FastAPI(Starlette): """ ), ] = "3.1.0" - self.openapi_schema: Optional[Dict[str, Any]] = None + self.openapi_schema: Optional[dict[str, Any]] = None if self.openapi_url: assert self.title, "A title must be provided for OpenAPI, e.g.: 'My API'" assert self.version, "A version must be provided for OpenAPI, e.g.: '2.1.0'" @@ -949,7 +945,7 @@ class FastAPI(Starlette): ), ] = State() self.dependency_overrides: Annotated[ - Dict[Callable[..., Any], Callable[..., Any]], + dict[Callable[..., Any], Callable[..., Any]], Doc( """ A dictionary with overrides for the dependencies. @@ -980,7 +976,7 @@ class FastAPI(Starlette): responses=responses, generate_unique_id_function=generate_unique_id_function, ) - self.exception_handlers: Dict[ + self.exception_handlers: dict[ Any, Callable[[Request, Any], Union[Response, Awaitable[Response]]] ] = {} if exception_handlers is None else dict(exception_handlers) self.exception_handlers.setdefault(HTTPException, http_exception_handler) @@ -993,7 +989,7 @@ class FastAPI(Starlette): websocket_request_validation_exception_handler, # type: ignore ) - self.user_middleware: List[Middleware] = ( + self.user_middleware: list[Middleware] = ( [] if middleware is None else list(middleware) ) self.middleware_stack: Union[ASGIApp, None] = None @@ -1047,7 +1043,7 @@ class FastAPI(Starlette): app = cls(app, *args, **kwargs) return app - def openapi(self) -> Dict[str, Any]: + def openapi(self) -> dict[str, Any]: """ Generate the OpenAPI schema of the application. This is called by FastAPI internally. @@ -1145,14 +1141,14 @@ class FastAPI(Starlette): *, response_model: Any = Default(None), status_code: Optional[int] = None, - tags: Optional[List[Union[str, Enum]]] = None, + tags: Optional[list[Union[str, Enum]]] = None, dependencies: Optional[Sequence[Depends]] = None, summary: Optional[str] = None, description: Optional[str] = None, response_description: str = "Successful Response", - responses: Optional[Dict[Union[int, str], Dict[str, Any]]] = None, + responses: Optional[dict[Union[int, str], dict[str, Any]]] = None, deprecated: Optional[bool] = None, - methods: Optional[List[str]] = None, + methods: Optional[list[str]] = None, operation_id: Optional[str] = None, response_model_include: Optional[IncEx] = None, response_model_exclude: Optional[IncEx] = None, @@ -1161,11 +1157,11 @@ class FastAPI(Starlette): response_model_exclude_defaults: bool = False, response_model_exclude_none: bool = False, include_in_schema: bool = True, - response_class: Union[Type[Response], DefaultPlaceholder] = Default( + response_class: Union[type[Response], DefaultPlaceholder] = Default( JSONResponse ), name: Optional[str] = None, - openapi_extra: Optional[Dict[str, Any]] = None, + openapi_extra: Optional[dict[str, Any]] = None, generate_unique_id_function: Callable[[routing.APIRoute], str] = Default( generate_unique_id ), @@ -1203,14 +1199,14 @@ class FastAPI(Starlette): *, response_model: Any = Default(None), status_code: Optional[int] = None, - tags: Optional[List[Union[str, Enum]]] = None, + tags: Optional[list[Union[str, Enum]]] = None, dependencies: Optional[Sequence[Depends]] = None, summary: Optional[str] = None, description: Optional[str] = None, response_description: str = "Successful Response", - responses: Optional[Dict[Union[int, str], Dict[str, Any]]] = None, + responses: Optional[dict[Union[int, str], dict[str, Any]]] = None, deprecated: Optional[bool] = None, - methods: Optional[List[str]] = None, + methods: Optional[list[str]] = None, operation_id: Optional[str] = None, response_model_include: Optional[IncEx] = None, response_model_exclude: Optional[IncEx] = None, @@ -1219,9 +1215,9 @@ class FastAPI(Starlette): response_model_exclude_defaults: bool = False, response_model_exclude_none: bool = False, include_in_schema: bool = True, - response_class: Type[Response] = Default(JSONResponse), + response_class: type[Response] = Default(JSONResponse), name: Optional[str] = None, - openapi_extra: Optional[Dict[str, Any]] = None, + openapi_extra: Optional[dict[str, Any]] = None, generate_unique_id_function: Callable[[routing.APIRoute], str] = Default( generate_unique_id ), @@ -1343,7 +1339,7 @@ class FastAPI(Starlette): *, prefix: Annotated[str, Doc("An optional path prefix for the router.")] = "", tags: Annotated[ - Optional[List[Union[str, Enum]]], + Optional[list[Union[str, Enum]]], Doc( """ A list of tags to be applied to all the *path operations* in this @@ -1385,7 +1381,7 @@ class FastAPI(Starlette): ), ] = None, responses: Annotated[ - Optional[Dict[Union[int, str], Dict[str, Any]]], + Optional[dict[Union[int, str], dict[str, Any]]], Doc( """ Additional responses to be shown in OpenAPI. @@ -1452,7 +1448,7 @@ class FastAPI(Starlette): ), ] = True, default_response_class: Annotated[ - Type[Response], + type[Response], Doc( """ Default response class to be used for the *path operations* in this @@ -1480,7 +1476,7 @@ class FastAPI(Starlette): ), ] = Default(JSONResponse), callbacks: Annotated[ - Optional[List[BaseRoute]], + Optional[list[BaseRoute]], Doc( """ List of *path operations* that will be used as OpenAPI callbacks. @@ -1603,7 +1599,7 @@ class FastAPI(Starlette): ), ] = None, tags: Annotated[ - Optional[List[Union[str, Enum]]], + Optional[list[Union[str, Enum]]], Doc( """ A list of tags to be applied to the *path operation*. @@ -1669,7 +1665,7 @@ class FastAPI(Starlette): ), ] = "Successful Response", responses: Annotated[ - Optional[Dict[Union[int, str], Dict[str, Any]]], + Optional[dict[Union[int, str], dict[str, Any]]], Doc( """ Additional responses that could be returned by this *path operation*. @@ -1810,7 +1806,7 @@ class FastAPI(Starlette): ), ] = True, response_class: Annotated[ - Type[Response], + type[Response], Doc( """ Response class to be used for this *path operation*. @@ -1831,7 +1827,7 @@ class FastAPI(Starlette): ), ] = None, callbacks: Annotated[ - Optional[List[BaseRoute]], + Optional[list[BaseRoute]], Doc( """ List of *path operations* that will be used as OpenAPI callbacks. @@ -1847,7 +1843,7 @@ class FastAPI(Starlette): ), ] = None, openapi_extra: Annotated[ - Optional[Dict[str, Any]], + Optional[dict[str, Any]], Doc( """ Extra metadata to be included in the OpenAPI schema for this *path @@ -1976,7 +1972,7 @@ class FastAPI(Starlette): ), ] = None, tags: Annotated[ - Optional[List[Union[str, Enum]]], + Optional[list[Union[str, Enum]]], Doc( """ A list of tags to be applied to the *path operation*. @@ -2042,7 +2038,7 @@ class FastAPI(Starlette): ), ] = "Successful Response", responses: Annotated[ - Optional[Dict[Union[int, str], Dict[str, Any]]], + Optional[dict[Union[int, str], dict[str, Any]]], Doc( """ Additional responses that could be returned by this *path operation*. @@ -2183,7 +2179,7 @@ class FastAPI(Starlette): ), ] = True, response_class: Annotated[ - Type[Response], + type[Response], Doc( """ Response class to be used for this *path operation*. @@ -2204,7 +2200,7 @@ class FastAPI(Starlette): ), ] = None, callbacks: Annotated[ - Optional[List[BaseRoute]], + Optional[list[BaseRoute]], Doc( """ List of *path operations* that will be used as OpenAPI callbacks. @@ -2220,7 +2216,7 @@ class FastAPI(Starlette): ), ] = None, openapi_extra: Annotated[ - Optional[Dict[str, Any]], + Optional[dict[str, Any]], Doc( """ Extra metadata to be included in the OpenAPI schema for this *path @@ -2354,7 +2350,7 @@ class FastAPI(Starlette): ), ] = None, tags: Annotated[ - Optional[List[Union[str, Enum]]], + Optional[list[Union[str, Enum]]], Doc( """ A list of tags to be applied to the *path operation*. @@ -2420,7 +2416,7 @@ class FastAPI(Starlette): ), ] = "Successful Response", responses: Annotated[ - Optional[Dict[Union[int, str], Dict[str, Any]]], + Optional[dict[Union[int, str], dict[str, Any]]], Doc( """ Additional responses that could be returned by this *path operation*. @@ -2561,7 +2557,7 @@ class FastAPI(Starlette): ), ] = True, response_class: Annotated[ - Type[Response], + type[Response], Doc( """ Response class to be used for this *path operation*. @@ -2582,7 +2578,7 @@ class FastAPI(Starlette): ), ] = None, callbacks: Annotated[ - Optional[List[BaseRoute]], + Optional[list[BaseRoute]], Doc( """ List of *path operations* that will be used as OpenAPI callbacks. @@ -2598,7 +2594,7 @@ class FastAPI(Starlette): ), ] = None, openapi_extra: Annotated[ - Optional[Dict[str, Any]], + Optional[dict[str, Any]], Doc( """ Extra metadata to be included in the OpenAPI schema for this *path @@ -2732,7 +2728,7 @@ class FastAPI(Starlette): ), ] = None, tags: Annotated[ - Optional[List[Union[str, Enum]]], + Optional[list[Union[str, Enum]]], Doc( """ A list of tags to be applied to the *path operation*. @@ -2798,7 +2794,7 @@ class FastAPI(Starlette): ), ] = "Successful Response", responses: Annotated[ - Optional[Dict[Union[int, str], Dict[str, Any]]], + Optional[dict[Union[int, str], dict[str, Any]]], Doc( """ Additional responses that could be returned by this *path operation*. @@ -2939,7 +2935,7 @@ class FastAPI(Starlette): ), ] = True, response_class: Annotated[ - Type[Response], + type[Response], Doc( """ Response class to be used for this *path operation*. @@ -2960,7 +2956,7 @@ class FastAPI(Starlette): ), ] = None, callbacks: Annotated[ - Optional[List[BaseRoute]], + Optional[list[BaseRoute]], Doc( """ List of *path operations* that will be used as OpenAPI callbacks. @@ -2976,7 +2972,7 @@ class FastAPI(Starlette): ), ] = None, openapi_extra: Annotated[ - Optional[Dict[str, Any]], + Optional[dict[str, Any]], Doc( """ Extra metadata to be included in the OpenAPI schema for this *path @@ -3105,7 +3101,7 @@ class FastAPI(Starlette): ), ] = None, tags: Annotated[ - Optional[List[Union[str, Enum]]], + Optional[list[Union[str, Enum]]], Doc( """ A list of tags to be applied to the *path operation*. @@ -3171,7 +3167,7 @@ class FastAPI(Starlette): ), ] = "Successful Response", responses: Annotated[ - Optional[Dict[Union[int, str], Dict[str, Any]]], + Optional[dict[Union[int, str], dict[str, Any]]], Doc( """ Additional responses that could be returned by this *path operation*. @@ -3312,7 +3308,7 @@ class FastAPI(Starlette): ), ] = True, response_class: Annotated[ - Type[Response], + type[Response], Doc( """ Response class to be used for this *path operation*. @@ -3333,7 +3329,7 @@ class FastAPI(Starlette): ), ] = None, callbacks: Annotated[ - Optional[List[BaseRoute]], + Optional[list[BaseRoute]], Doc( """ List of *path operations* that will be used as OpenAPI callbacks. @@ -3349,7 +3345,7 @@ class FastAPI(Starlette): ), ] = None, openapi_extra: Annotated[ - Optional[Dict[str, Any]], + Optional[dict[str, Any]], Doc( """ Extra metadata to be included in the OpenAPI schema for this *path @@ -3478,7 +3474,7 @@ class FastAPI(Starlette): ), ] = None, tags: Annotated[ - Optional[List[Union[str, Enum]]], + Optional[list[Union[str, Enum]]], Doc( """ A list of tags to be applied to the *path operation*. @@ -3544,7 +3540,7 @@ class FastAPI(Starlette): ), ] = "Successful Response", responses: Annotated[ - Optional[Dict[Union[int, str], Dict[str, Any]]], + Optional[dict[Union[int, str], dict[str, Any]]], Doc( """ Additional responses that could be returned by this *path operation*. @@ -3685,7 +3681,7 @@ class FastAPI(Starlette): ), ] = True, response_class: Annotated[ - Type[Response], + type[Response], Doc( """ Response class to be used for this *path operation*. @@ -3706,7 +3702,7 @@ class FastAPI(Starlette): ), ] = None, callbacks: Annotated[ - Optional[List[BaseRoute]], + Optional[list[BaseRoute]], Doc( """ List of *path operations* that will be used as OpenAPI callbacks. @@ -3722,7 +3718,7 @@ class FastAPI(Starlette): ), ] = None, openapi_extra: Annotated[ - Optional[Dict[str, Any]], + Optional[dict[str, Any]], Doc( """ Extra metadata to be included in the OpenAPI schema for this *path @@ -3851,7 +3847,7 @@ class FastAPI(Starlette): ), ] = None, tags: Annotated[ - Optional[List[Union[str, Enum]]], + Optional[list[Union[str, Enum]]], Doc( """ A list of tags to be applied to the *path operation*. @@ -3917,7 +3913,7 @@ class FastAPI(Starlette): ), ] = "Successful Response", responses: Annotated[ - Optional[Dict[Union[int, str], Dict[str, Any]]], + Optional[dict[Union[int, str], dict[str, Any]]], Doc( """ Additional responses that could be returned by this *path operation*. @@ -4058,7 +4054,7 @@ class FastAPI(Starlette): ), ] = True, response_class: Annotated[ - Type[Response], + type[Response], Doc( """ Response class to be used for this *path operation*. @@ -4079,7 +4075,7 @@ class FastAPI(Starlette): ), ] = None, callbacks: Annotated[ - Optional[List[BaseRoute]], + Optional[list[BaseRoute]], Doc( """ List of *path operations* that will be used as OpenAPI callbacks. @@ -4095,7 +4091,7 @@ class FastAPI(Starlette): ), ] = None, openapi_extra: Annotated[ - Optional[Dict[str, Any]], + Optional[dict[str, Any]], Doc( """ Extra metadata to be included in the OpenAPI schema for this *path @@ -4229,7 +4225,7 @@ class FastAPI(Starlette): ), ] = None, tags: Annotated[ - Optional[List[Union[str, Enum]]], + Optional[list[Union[str, Enum]]], Doc( """ A list of tags to be applied to the *path operation*. @@ -4295,7 +4291,7 @@ class FastAPI(Starlette): ), ] = "Successful Response", responses: Annotated[ - Optional[Dict[Union[int, str], Dict[str, Any]]], + Optional[dict[Union[int, str], dict[str, Any]]], Doc( """ Additional responses that could be returned by this *path operation*. @@ -4436,7 +4432,7 @@ class FastAPI(Starlette): ), ] = True, response_class: Annotated[ - Type[Response], + type[Response], Doc( """ Response class to be used for this *path operation*. @@ -4457,7 +4453,7 @@ class FastAPI(Starlette): ), ] = None, callbacks: Annotated[ - Optional[List[BaseRoute]], + Optional[list[BaseRoute]], Doc( """ List of *path operations* that will be used as OpenAPI callbacks. @@ -4473,7 +4469,7 @@ class FastAPI(Starlette): ), ] = None, openapi_extra: Annotated[ - Optional[Dict[str, Any]], + Optional[dict[str, Any]], Doc( """ Extra metadata to be included in the OpenAPI schema for this *path @@ -4628,7 +4624,7 @@ class FastAPI(Starlette): def exception_handler( self, exc_class_or_status_code: Annotated[ - Union[int, Type[Exception]], + Union[int, type[Exception]], Doc( """ The Exception class this would handle, or a status code. diff --git a/fastapi/background.py b/fastapi/background.py index 6d4a30d442..20803ba670 100644 --- a/fastapi/background.py +++ b/fastapi/background.py @@ -1,8 +1,8 @@ -from typing import Any, Callable +from typing import Annotated, Any, Callable from annotated_doc import Doc from starlette.background import BackgroundTasks as StarletteBackgroundTasks -from typing_extensions import Annotated, ParamSpec +from typing_extensions import ParamSpec P = ParamSpec("P") diff --git a/fastapi/concurrency.py b/fastapi/concurrency.py index 3202c70789..76a5a2eb12 100644 --- a/fastapi/concurrency.py +++ b/fastapi/concurrency.py @@ -1,5 +1,7 @@ +from collections.abc import AsyncGenerator +from contextlib import AbstractContextManager from contextlib import asynccontextmanager as asynccontextmanager -from typing import AsyncGenerator, ContextManager, TypeVar +from typing import TypeVar import anyio.to_thread from anyio import CapacityLimiter @@ -14,7 +16,7 @@ _T = TypeVar("_T") @asynccontextmanager async def contextmanager_in_threadpool( - cm: ContextManager[_T], + cm: AbstractContextManager[_T], ) -> AsyncGenerator[_T, None]: # blocking __exit__ from running waiting on a free thread # can create race conditions/deadlocks if the context manager itself diff --git a/fastapi/datastructures.py b/fastapi/datastructures.py index 8ad9aa11a6..b38a326def 100644 --- a/fastapi/datastructures.py +++ b/fastapi/datastructures.py @@ -1,11 +1,10 @@ +from collections.abc import Iterable from typing import ( + Annotated, Any, BinaryIO, Callable, - Dict, - Iterable, Optional, - Type, TypeVar, cast, ) @@ -23,7 +22,6 @@ 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 class UploadFile(StarletteUploadFile): @@ -138,11 +136,11 @@ class UploadFile(StarletteUploadFile): return await super().close() @classmethod - def __get_validators__(cls: Type["UploadFile"]) -> Iterable[Callable[..., Any]]: + def __get_validators__(cls: type["UploadFile"]) -> Iterable[Callable[..., Any]]: yield cls.validate @classmethod - def validate(cls: Type["UploadFile"], v: Any) -> Any: + def validate(cls: type["UploadFile"], v: Any) -> Any: if not isinstance(v, StarletteUploadFile): raise ValueError(f"Expected UploadFile, received: {type(v)}") return v @@ -155,7 +153,7 @@ class UploadFile(StarletteUploadFile): # TODO: remove when deprecating Pydantic v1 @classmethod - def __modify_schema__(cls, field_schema: Dict[str, Any]) -> None: + def __modify_schema__(cls, field_schema: dict[str, Any]) -> None: field_schema.update({"type": "string", "format": "binary"}) @classmethod @@ -166,7 +164,7 @@ class UploadFile(StarletteUploadFile): @classmethod def __get_pydantic_core_schema__( - cls, source: Type[Any], handler: Callable[[Any], CoreSchema] + cls, source: type[Any], handler: Callable[[Any], CoreSchema] ) -> CoreSchema: from ._compat.v2 import with_info_plain_validator_function diff --git a/fastapi/dependencies/models.py b/fastapi/dependencies/models.py index 6c4bf18b37..58392326d6 100644 --- a/fastapi/dependencies/models.py +++ b/fastapi/dependencies/models.py @@ -2,7 +2,7 @@ import inspect import sys from dataclasses import dataclass, field from functools import cached_property, partial -from typing import Any, Callable, List, Optional, Union +from typing import Any, Callable, Optional, Union from fastapi._compat import ModelField from fastapi.security.base import SecurityBase @@ -30,12 +30,12 @@ def _impartial(func: Callable[..., Any]) -> Callable[..., Any]: @dataclass class Dependant: - path_params: List[ModelField] = field(default_factory=list) - query_params: List[ModelField] = field(default_factory=list) - header_params: List[ModelField] = field(default_factory=list) - cookie_params: List[ModelField] = field(default_factory=list) - body_params: List[ModelField] = field(default_factory=list) - dependencies: List["Dependant"] = field(default_factory=list) + path_params: list[ModelField] = field(default_factory=list) + query_params: list[ModelField] = field(default_factory=list) + header_params: list[ModelField] = field(default_factory=list) + cookie_params: list[ModelField] = field(default_factory=list) + body_params: list[ModelField] = field(default_factory=list) + dependencies: list["Dependant"] = field(default_factory=list) name: Optional[str] = None call: Optional[Callable[..., Any]] = None request_param_name: Optional[str] = None @@ -44,14 +44,14 @@ class Dependant: response_param_name: Optional[str] = None background_tasks_param_name: Optional[str] = None security_scopes_param_name: Optional[str] = None - own_oauth_scopes: Optional[List[str]] = None - parent_oauth_scopes: Optional[List[str]] = None + own_oauth_scopes: Optional[list[str]] = None + parent_oauth_scopes: Optional[list[str]] = None use_cache: bool = True path: Optional[str] = None scope: Union[Literal["function", "request"], None] = None @cached_property - def oauth_scopes(self) -> List[str]: + def oauth_scopes(self) -> list[str]: scopes = self.parent_oauth_scopes.copy() if self.parent_oauth_scopes else [] # This doesn't use a set to preserve order, just in case for scope in self.own_oauth_scopes or []: @@ -98,7 +98,7 @@ class Dependant: return unwrapped @cached_property - def _security_dependencies(self) -> List["Dependant"]: + def _security_dependencies(self) -> list["Dependant"]: security_deps = [dep for dep in self.dependencies if dep._is_security_scheme] return security_deps diff --git a/fastapi/dependencies/utils.py b/fastapi/dependencies/utils.py index daaf6a9904..706533055c 100644 --- a/fastapi/dependencies/utils.py +++ b/fastapi/dependencies/utils.py @@ -1,21 +1,16 @@ import dataclasses import inspect import sys +from collections.abc import Coroutine, Mapping, Sequence from contextlib import AsyncExitStack, contextmanager from copy import copy, deepcopy from dataclasses import dataclass from typing import ( + Annotated, Any, Callable, - Coroutine, - Dict, ForwardRef, - List, - Mapping, Optional, - Sequence, - Tuple, - Type, Union, cast, ) @@ -75,7 +70,7 @@ 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, Literal, get_args, get_origin +from typing_extensions import Literal, get_args, get_origin from .. import temp_pydantic_v1_params @@ -125,7 +120,7 @@ def get_parameterless_sub_dependant(*, depends: params.Depends, path: str) -> De assert callable(depends.dependency), ( "A parameter-less dependency must have a callable dependency" ) - own_oauth_scopes: List[str] = [] + own_oauth_scopes: list[str] = [] if isinstance(depends, params.Security) and depends.scopes: own_oauth_scopes.extend(depends.scopes) return get_dependant( @@ -140,8 +135,8 @@ def get_flat_dependant( dependant: Dependant, *, skip_repeats: bool = False, - visited: Optional[List[DependencyCacheKey]] = None, - parent_oauth_scopes: Optional[List[str]] = None, + visited: Optional[list[DependencyCacheKey]] = None, + parent_oauth_scopes: Optional[list[str]] = None, ) -> Dependant: if visited is None: visited = [] @@ -190,7 +185,7 @@ def get_flat_dependant( return flat_dependant -def _get_flat_fields_from_params(fields: List[ModelField]) -> List[ModelField]: +def _get_flat_fields_from_params(fields: list[ModelField]) -> list[ModelField]: if not fields: return fields first_field = fields[0] @@ -200,7 +195,7 @@ def _get_flat_fields_from_params(fields: List[ModelField]) -> List[ModelField]: return fields -def get_flat_params(dependant: Dependant) -> List[ModelField]: +def get_flat_params(dependant: Dependant) -> list[ModelField]: flat_dependant = get_flat_dependant(dependant, skip_repeats=True) path_params = _get_flat_fields_from_params(flat_dependant.path_params) query_params = _get_flat_fields_from_params(flat_dependant.query_params) @@ -255,7 +250,7 @@ def get_typed_signature(call: Callable[..., Any]) -> inspect.Signature: return typed_signature -def get_typed_annotation(annotation: Any, globalns: Dict[str, Any]) -> Any: +def get_typed_annotation(annotation: Any, globalns: dict[str, Any]) -> Any: if isinstance(annotation, str): # Special handling for Annotated types with forward references # When using `from __future__ import annotations`, the entire annotation @@ -387,8 +382,8 @@ def get_dependant( path: str, call: Callable[..., Any], name: Optional[str] = None, - own_oauth_scopes: Optional[List[str]] = None, - parent_oauth_scopes: Optional[List[str]] = None, + own_oauth_scopes: Optional[list[str]] = None, + parent_oauth_scopes: Optional[list[str]] = None, use_cache: bool = True, scope: Union[Literal["function", "request"], None] = None, ) -> Dependant: @@ -425,7 +420,7 @@ def get_dependant( f'The dependency "{dependant.call.__name__}" has a scope of ' '"request", it cannot depend on dependencies with scope "function".' ) - sub_own_oauth_scopes: List[str] = [] + sub_own_oauth_scopes: list[str] = [] if isinstance(param_details.depends, params.Security): if param_details.depends.scopes: sub_own_oauth_scopes = list(param_details.depends.scopes) @@ -694,7 +689,7 @@ def add_param_to_fields(*, field: ModelField, dependant: Dependant) -> None: async def _solve_generator( - *, dependant: Dependant, stack: AsyncExitStack, sub_values: Dict[str, Any] + *, dependant: Dependant, stack: AsyncExitStack, sub_values: dict[str, Any] ) -> Any: assert dependant.call if dependant.is_async_gen_callable: @@ -706,22 +701,22 @@ async def _solve_generator( @dataclass class SolvedDependency: - values: Dict[str, Any] - errors: List[Any] + values: dict[str, Any] + errors: list[Any] background_tasks: Optional[StarletteBackgroundTasks] response: Response - dependency_cache: Dict[DependencyCacheKey, Any] + dependency_cache: dict[DependencyCacheKey, Any] async def solve_dependencies( *, request: Union[Request, WebSocket], dependant: Dependant, - body: Optional[Union[Dict[str, Any], FormData]] = None, + body: Optional[Union[dict[str, Any], FormData]] = None, background_tasks: Optional[StarletteBackgroundTasks] = None, response: Optional[Response] = None, dependency_overrides_provider: Optional[Any] = None, - dependency_cache: Optional[Dict[DependencyCacheKey, 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, @@ -735,8 +730,8 @@ async def solve_dependencies( assert isinstance(function_astack, AsyncExitStack), ( "fastapi_function_astack not found in request scope" ) - values: Dict[str, Any] = {} - errors: List[Any] = [] + values: dict[str, Any] = {} + errors: list[Any] = [] if response is None: response = Response() del response.headers["content-length"] @@ -854,8 +849,8 @@ async def solve_dependencies( def _validate_value_with_model_field( - *, field: ModelField, value: Any, values: Dict[str, Any], loc: Tuple[str, ...] -) -> Tuple[Any, List[Any]]: + *, field: ModelField, value: Any, values: dict[str, Any], loc: tuple[str, ...] +) -> tuple[Any, list[Any]]: if value is None: if field.required: return None, [get_missing_field_error(loc=loc)] @@ -898,9 +893,9 @@ def _get_multidict_value( def request_params_to_args( fields: Sequence[ModelField], received_params: Union[Mapping[str, Any], QueryParams, Headers], -) -> Tuple[Dict[str, Any], List[Any]]: - values: Dict[str, Any] = {} - errors: List[Dict[str, Any]] = [] +) -> tuple[dict[str, Any], list[Any]]: + values: dict[str, Any] = {} + errors: list[dict[str, Any]] = [] if not fields: return values, errors @@ -918,7 +913,7 @@ def request_params_to_args( first_field.field_info, "convert_underscores", True ) - params_to_process: Dict[str, Any] = {} + params_to_process: dict[str, Any] = {} processed_keys = set() @@ -955,7 +950,7 @@ def request_params_to_args( assert isinstance(field_info, (params.Param, temp_pydantic_v1_params.Param)), ( "Params must be subclasses of Param" ) - loc: Tuple[str, ...] = (field_info.in_.value,) + loc: tuple[str, ...] = (field_info.in_.value,) v_, errors_ = _validate_value_with_model_field( field=first_field, value=params_to_process, values=values, loc=loc ) @@ -997,7 +992,7 @@ def is_union_of_base_models(field_type: Any) -> bool: return True -def _should_embed_body_fields(fields: List[ModelField]) -> bool: +def _should_embed_body_fields(fields: list[ModelField]) -> bool: if not fields: return False # More than one dependency could have the same field, it would show up as multiple @@ -1022,9 +1017,9 @@ def _should_embed_body_fields(fields: List[ModelField]) -> bool: async def _extract_form_body( - body_fields: List[ModelField], + body_fields: list[ModelField], received_body: FormData, -) -> Dict[str, Any]: +) -> dict[str, Any]: values = {} for field in body_fields: @@ -1042,8 +1037,8 @@ async def _extract_form_body( and value_is_sequence(value) ): # For types - assert isinstance(value, sequence_types) # type: ignore[arg-type] - results: List[Union[bytes, str]] = [] + assert isinstance(value, sequence_types) + results: list[Union[bytes, str]] = [] async def process_fn( fn: Callable[[], Coroutine[Any, Any, Any]], @@ -1069,18 +1064,18 @@ async def _extract_form_body( async def request_body_to_args( - body_fields: List[ModelField], - received_body: Optional[Union[Dict[str, Any], FormData]], + body_fields: list[ModelField], + received_body: Optional[Union[dict[str, Any], FormData]], embed_body_fields: bool, -) -> Tuple[Dict[str, Any], List[Dict[str, Any]]]: - values: Dict[str, Any] = {} - errors: List[Dict[str, Any]] = [] +) -> tuple[dict[str, Any], list[dict[str, Any]]]: + values: dict[str, Any] = {} + errors: list[dict[str, Any]] = [] assert body_fields, "request_body_to_args() should be called with fields" single_not_embedded_field = len(body_fields) == 1 and not embed_body_fields first_field = body_fields[0] body_to_process = received_body - fields_to_extract: List[ModelField] = body_fields + fields_to_extract: list[ModelField] = body_fields if ( single_not_embedded_field @@ -1093,7 +1088,7 @@ async def request_body_to_args( body_to_process = await _extract_form_body(fields_to_extract, received_body) if single_not_embedded_field: - loc: Tuple[str, ...] = ("body",) + loc: tuple[str, ...] = ("body",) v_, errors_ = _validate_value_with_model_field( field=first_field, value=body_to_process, values=values, loc=loc ) @@ -1141,19 +1136,19 @@ def get_body_field( fields=flat_dependant.body_params, model_name=model_name ) required = any(True for f in flat_dependant.body_params if f.required) - BodyFieldInfo_kwargs: Dict[str, Any] = { + BodyFieldInfo_kwargs: dict[str, Any] = { "annotation": BodyModel, "alias": "body", } if not required: BodyFieldInfo_kwargs["default"] = None if any(isinstance(f.field_info, params.File) for f in flat_dependant.body_params): - BodyFieldInfo: Type[params.Body] = params.File + BodyFieldInfo: type[params.Body] = params.File elif any( isinstance(f.field_info, temp_pydantic_v1_params.File) for f in flat_dependant.body_params ): - BodyFieldInfo: Type[temp_pydantic_v1_params.Body] = temp_pydantic_v1_params.File # type: ignore[no-redef] + BodyFieldInfo: type[temp_pydantic_v1_params.Body] = temp_pydantic_v1_params.File # type: ignore[no-redef] elif any(isinstance(f.field_info, params.Form) for f in flat_dependant.body_params): BodyFieldInfo = params.Form elif any( diff --git a/fastapi/encoders.py b/fastapi/encoders.py index 7939510895..cbeeee4559 100644 --- a/fastapi/encoders.py +++ b/fastapi/encoders.py @@ -14,7 +14,7 @@ from ipaddress import ( from pathlib import Path, PurePath from re import Pattern from types import GeneratorType -from typing import Any, Callable, Dict, List, Optional, Tuple, Type, Union +from typing import Annotated, Any, Callable, Optional, Union from uuid import UUID from annotated_doc import Doc @@ -24,7 +24,6 @@ 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 from ._compat import Url, _is_undefined, _model_dump @@ -61,7 +60,7 @@ def decimal_encoder(dec_value: Decimal) -> Union[int, float]: return float(dec_value) -ENCODERS_BY_TYPE: Dict[Type[Any], Callable[[Any], Any]] = { +ENCODERS_BY_TYPE: dict[type[Any], Callable[[Any], Any]] = { bytes: lambda o: o.decode(), Color: str, may_v1.Color: str, @@ -98,9 +97,9 @@ ENCODERS_BY_TYPE: Dict[Type[Any], Callable[[Any], Any]] = { def generate_encoders_by_class_tuples( - type_encoder_map: Dict[Any, Callable[[Any], Any]], -) -> Dict[Callable[[Any], Any], Tuple[Any, ...]]: - encoders_by_class_tuples: Dict[Callable[[Any], Any], Tuple[Any, ...]] = defaultdict( + type_encoder_map: dict[Any, Callable[[Any], Any]], +) -> dict[Callable[[Any], Any], tuple[Any, ...]]: + encoders_by_class_tuples: dict[Callable[[Any], Any], tuple[Any, ...]] = defaultdict( tuple ) for type_, encoder in type_encoder_map.items(): @@ -180,7 +179,7 @@ def jsonable_encoder( ), ] = False, custom_encoder: Annotated[ - Optional[Dict[Any, Callable[[Any], Any]]], + Optional[dict[Any, Callable[[Any], Any]]], Doc( """ Pydantic's `custom_encoder` parameter, passed to Pydantic models to define @@ -227,7 +226,7 @@ def jsonable_encoder( exclude = set(exclude) if isinstance(obj, (BaseModel, may_v1.BaseModel)): # TODO: remove when deprecating Pydantic v1 - encoders: Dict[Any, Any] = {} + encoders: dict[Any, Any] = {} if isinstance(obj, may_v1.BaseModel): encoders = getattr(obj.__config__, "json_encoders", {}) # type: ignore[attr-defined] if custom_encoder: @@ -336,7 +335,7 @@ def jsonable_encoder( try: data = dict(obj) except Exception as e: - errors: List[Exception] = [] + errors: list[Exception] = [] errors.append(e) try: data = vars(obj) diff --git a/fastapi/exceptions.py b/fastapi/exceptions.py index a46e823506..8e0c559023 100644 --- a/fastapi/exceptions.py +++ b/fastapi/exceptions.py @@ -1,10 +1,10 @@ -from typing import Any, Dict, Optional, Sequence, Type, TypedDict, Union +from collections.abc import Sequence +from typing import Annotated, Any, Optional, TypedDict, 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 class EndpointContext(TypedDict, total=False): @@ -62,7 +62,7 @@ class HTTPException(StarletteHTTPException): ), ] = None, headers: Annotated[ - Optional[Dict[str, str]], + Optional[dict[str, str]], Doc( """ Any headers to send to the client in the response. @@ -144,8 +144,8 @@ class WebSocketException(StarletteWebSocketException): super().__init__(code=code, reason=reason) -RequestErrorModel: Type[BaseModel] = create_model("Request") -WebSocketErrorModel: Type[BaseModel] = create_model("WebSocket") +RequestErrorModel: type[BaseModel] = create_model("Request") +WebSocketErrorModel: type[BaseModel] = create_model("WebSocket") class FastAPIError(RuntimeError): diff --git a/fastapi/openapi/docs.py b/fastapi/openapi/docs.py index 74b23a3706..82380f85d9 100644 --- a/fastapi/openapi/docs.py +++ b/fastapi/openapi/docs.py @@ -1,13 +1,12 @@ import json -from typing import Any, Dict, Optional +from typing import Annotated, Any, Optional from annotated_doc import Doc from fastapi.encoders import jsonable_encoder from starlette.responses import HTMLResponse -from typing_extensions import Annotated swagger_ui_default_parameters: Annotated[ - Dict[str, Any], + dict[str, Any], Doc( """ Default configurations for Swagger UI. @@ -82,7 +81,7 @@ def get_swagger_ui_html( ), ] = None, init_oauth: Annotated[ - Optional[Dict[str, Any]], + Optional[dict[str, Any]], Doc( """ A dictionary with Swagger UI OAuth2 initialization configurations. @@ -90,7 +89,7 @@ def get_swagger_ui_html( ), ] = None, swagger_ui_parameters: Annotated[ - Optional[Dict[str, Any]], + Optional[dict[str, Any]], Doc( """ Configuration parameters for Swagger UI. diff --git a/fastapi/openapi/models.py b/fastapi/openapi/models.py index 81d276aed6..7aa80f5cb0 100644 --- a/fastapi/openapi/models.py +++ b/fastapi/openapi/models.py @@ -1,5 +1,6 @@ +from collections.abc import Iterable from enum import Enum -from typing import Any, Callable, Dict, Iterable, List, Optional, Set, Type, Union +from typing import Annotated, Any, Callable, Optional, Union from fastapi._compat import ( PYDANTIC_V2, @@ -11,7 +12,7 @@ from fastapi._compat import ( ) from fastapi.logger import logger from pydantic import AnyUrl, BaseModel, Field -from typing_extensions import Annotated, Literal, TypedDict +from typing_extensions import Literal, TypedDict from typing_extensions import deprecated as typing_deprecated try: @@ -50,7 +51,7 @@ except ImportError: # pragma: no cover @classmethod def __get_pydantic_core_schema__( - cls, source: Type[Any], handler: Callable[[Any], CoreSchema] + cls, source: type[Any], handler: Callable[[Any], CoreSchema] ) -> CoreSchema: return with_info_plain_validator_function(cls._validate) @@ -88,7 +89,7 @@ class Info(BaseModelWithConfig): class ServerVariable(BaseModelWithConfig): - enum: Annotated[Optional[List[str]], Field(min_length=1)] = None + enum: Annotated[Optional[list[str]], Field(min_length=1)] = None default: str description: Optional[str] = None @@ -96,7 +97,7 @@ class ServerVariable(BaseModelWithConfig): class Server(BaseModelWithConfig): url: Union[AnyUrl, str] description: Optional[str] = None - variables: Optional[Dict[str, ServerVariable]] = None + variables: Optional[dict[str, ServerVariable]] = None class Reference(BaseModel): @@ -105,7 +106,7 @@ class Reference(BaseModel): class Discriminator(BaseModel): propertyName: str - mapping: Optional[Dict[str, str]] = None + mapping: Optional[dict[str, str]] = None class XML(BaseModelWithConfig): @@ -137,34 +138,34 @@ class Schema(BaseModelWithConfig): dynamicAnchor: Optional[str] = Field(default=None, alias="$dynamicAnchor") ref: Optional[str] = Field(default=None, alias="$ref") dynamicRef: Optional[str] = Field(default=None, alias="$dynamicRef") - defs: Optional[Dict[str, "SchemaOrBool"]] = Field(default=None, alias="$defs") + defs: Optional[dict[str, "SchemaOrBool"]] = Field(default=None, alias="$defs") comment: Optional[str] = Field(default=None, alias="$comment") # Ref: JSON Schema 2020-12: https://json-schema.org/draft/2020-12/json-schema-core.html#name-a-vocabulary-for-applying-s # A Vocabulary for Applying Subschemas - allOf: Optional[List["SchemaOrBool"]] = None - anyOf: Optional[List["SchemaOrBool"]] = None - oneOf: Optional[List["SchemaOrBool"]] = None + allOf: Optional[list["SchemaOrBool"]] = None + anyOf: Optional[list["SchemaOrBool"]] = None + oneOf: Optional[list["SchemaOrBool"]] = None not_: Optional["SchemaOrBool"] = Field(default=None, alias="not") if_: Optional["SchemaOrBool"] = Field(default=None, alias="if") then: Optional["SchemaOrBool"] = None else_: Optional["SchemaOrBool"] = Field(default=None, alias="else") - dependentSchemas: Optional[Dict[str, "SchemaOrBool"]] = None - prefixItems: Optional[List["SchemaOrBool"]] = None + dependentSchemas: Optional[dict[str, "SchemaOrBool"]] = None + prefixItems: Optional[list["SchemaOrBool"]] = None # TODO: uncomment and remove below when deprecating Pydantic v1 # It generates a list of schemas for tuples, before prefixItems was available # items: Optional["SchemaOrBool"] = None - items: Optional[Union["SchemaOrBool", List["SchemaOrBool"]]] = None + items: Optional[Union["SchemaOrBool", list["SchemaOrBool"]]] = None contains: Optional["SchemaOrBool"] = None - properties: Optional[Dict[str, "SchemaOrBool"]] = None - patternProperties: Optional[Dict[str, "SchemaOrBool"]] = None + properties: Optional[dict[str, "SchemaOrBool"]] = None + patternProperties: Optional[dict[str, "SchemaOrBool"]] = None additionalProperties: Optional["SchemaOrBool"] = None propertyNames: Optional["SchemaOrBool"] = None unevaluatedItems: Optional["SchemaOrBool"] = None unevaluatedProperties: Optional["SchemaOrBool"] = None # Ref: JSON Schema Validation 2020-12: https://json-schema.org/draft/2020-12/json-schema-validation.html#name-a-vocabulary-for-structural # A Vocabulary for Structural Validation - type: Optional[Union[SchemaType, List[SchemaType]]] = None - enum: Optional[List[Any]] = None + type: Optional[Union[SchemaType, list[SchemaType]]] = None + enum: Optional[list[Any]] = None const: Optional[Any] = None multipleOf: Optional[float] = Field(default=None, gt=0) maximum: Optional[float] = None @@ -181,8 +182,8 @@ class Schema(BaseModelWithConfig): minContains: Optional[int] = Field(default=None, ge=0) maxProperties: Optional[int] = Field(default=None, ge=0) minProperties: Optional[int] = Field(default=None, ge=0) - required: Optional[List[str]] = None - dependentRequired: Optional[Dict[str, Set[str]]] = None + required: Optional[list[str]] = None + dependentRequired: Optional[dict[str, set[str]]] = None # Ref: JSON Schema Validation 2020-12: https://json-schema.org/draft/2020-12/json-schema-validation.html#name-vocabularies-for-semantic-c # Vocabularies for Semantic Content With "format" format: Optional[str] = None @@ -199,7 +200,7 @@ class Schema(BaseModelWithConfig): deprecated: Optional[bool] = None readOnly: Optional[bool] = None writeOnly: Optional[bool] = None - examples: Optional[List[Any]] = None + examples: Optional[list[Any]] = None # Ref: OpenAPI 3.1.0: https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#schema-object # Schema Object discriminator: Optional[Discriminator] = None @@ -243,7 +244,7 @@ class ParameterInType(Enum): class Encoding(BaseModelWithConfig): contentType: Optional[str] = None - headers: Optional[Dict[str, Union["Header", Reference]]] = None + headers: Optional[dict[str, Union["Header", Reference]]] = None style: Optional[str] = None explode: Optional[bool] = None allowReserved: Optional[bool] = None @@ -252,8 +253,8 @@ class Encoding(BaseModelWithConfig): class MediaType(BaseModelWithConfig): schema_: Optional[Union[Schema, Reference]] = Field(default=None, alias="schema") example: Optional[Any] = None - examples: Optional[Dict[str, Union[Example, Reference]]] = None - encoding: Optional[Dict[str, Encoding]] = None + examples: Optional[dict[str, Union[Example, Reference]]] = None + encoding: Optional[dict[str, Encoding]] = None class ParameterBase(BaseModelWithConfig): @@ -266,9 +267,9 @@ class ParameterBase(BaseModelWithConfig): allowReserved: Optional[bool] = None schema_: Optional[Union[Schema, Reference]] = Field(default=None, alias="schema") example: Optional[Any] = None - examples: Optional[Dict[str, Union[Example, Reference]]] = None + examples: Optional[dict[str, Union[Example, Reference]]] = None # Serialization rules for more complex scenarios - content: Optional[Dict[str, MediaType]] = None + content: Optional[dict[str, MediaType]] = None class Parameter(ParameterBase): @@ -282,14 +283,14 @@ class Header(ParameterBase): class RequestBody(BaseModelWithConfig): description: Optional[str] = None - content: Dict[str, MediaType] + content: dict[str, MediaType] required: Optional[bool] = None class Link(BaseModelWithConfig): operationRef: Optional[str] = None operationId: Optional[str] = None - parameters: Optional[Dict[str, Union[Any, str]]] = None + parameters: Optional[dict[str, Union[Any, str]]] = None requestBody: Optional[Union[Any, str]] = None description: Optional[str] = None server: Optional[Server] = None @@ -297,25 +298,25 @@ class Link(BaseModelWithConfig): class Response(BaseModelWithConfig): description: str - headers: Optional[Dict[str, Union[Header, Reference]]] = None - content: Optional[Dict[str, MediaType]] = None - links: Optional[Dict[str, Union[Link, Reference]]] = None + headers: Optional[dict[str, Union[Header, Reference]]] = None + content: Optional[dict[str, MediaType]] = None + links: Optional[dict[str, Union[Link, Reference]]] = None class Operation(BaseModelWithConfig): - tags: Optional[List[str]] = None + tags: Optional[list[str]] = None summary: Optional[str] = None description: Optional[str] = None externalDocs: Optional[ExternalDocumentation] = None operationId: Optional[str] = None - parameters: Optional[List[Union[Parameter, Reference]]] = None + parameters: Optional[list[Union[Parameter, Reference]]] = None requestBody: Optional[Union[RequestBody, Reference]] = None # Using Any for Specification Extensions - responses: Optional[Dict[str, Union[Response, Any]]] = None - callbacks: Optional[Dict[str, Union[Dict[str, "PathItem"], Reference]]] = None + responses: Optional[dict[str, Union[Response, Any]]] = None + callbacks: Optional[dict[str, Union[dict[str, "PathItem"], Reference]]] = None deprecated: Optional[bool] = None - security: Optional[List[Dict[str, List[str]]]] = None - servers: Optional[List[Server]] = None + security: Optional[list[dict[str, list[str]]]] = None + servers: Optional[list[Server]] = None class PathItem(BaseModelWithConfig): @@ -330,8 +331,8 @@ class PathItem(BaseModelWithConfig): head: Optional[Operation] = None patch: Optional[Operation] = None trace: Optional[Operation] = None - servers: Optional[List[Server]] = None - parameters: Optional[List[Union[Parameter, Reference]]] = None + servers: Optional[list[Server]] = None + parameters: Optional[list[Union[Parameter, Reference]]] = None class SecuritySchemeType(Enum): @@ -370,7 +371,7 @@ class HTTPBearer(HTTPBase): class OAuthFlow(BaseModelWithConfig): refreshUrl: Optional[str] = None - scopes: Dict[str, str] = {} + scopes: dict[str, str] = {} class OAuthFlowImplicit(OAuthFlow): @@ -413,17 +414,17 @@ SecurityScheme = Union[APIKey, HTTPBase, OAuth2, OpenIdConnect, HTTPBearer] class Components(BaseModelWithConfig): - schemas: Optional[Dict[str, Union[Schema, Reference]]] = None - responses: Optional[Dict[str, Union[Response, Reference]]] = None - parameters: Optional[Dict[str, Union[Parameter, Reference]]] = None - examples: Optional[Dict[str, Union[Example, Reference]]] = None - requestBodies: Optional[Dict[str, Union[RequestBody, Reference]]] = None - headers: Optional[Dict[str, Union[Header, Reference]]] = None - securitySchemes: Optional[Dict[str, Union[SecurityScheme, Reference]]] = None - links: Optional[Dict[str, Union[Link, Reference]]] = None + schemas: Optional[dict[str, Union[Schema, Reference]]] = None + responses: Optional[dict[str, Union[Response, Reference]]] = None + parameters: Optional[dict[str, Union[Parameter, Reference]]] = None + examples: Optional[dict[str, Union[Example, Reference]]] = None + requestBodies: Optional[dict[str, Union[RequestBody, Reference]]] = None + headers: Optional[dict[str, Union[Header, Reference]]] = None + securitySchemes: Optional[dict[str, Union[SecurityScheme, Reference]]] = None + links: Optional[dict[str, Union[Link, Reference]]] = None # Using Any for Specification Extensions - callbacks: Optional[Dict[str, Union[Dict[str, PathItem], Reference, Any]]] = None - pathItems: Optional[Dict[str, Union[PathItem, Reference]]] = None + callbacks: Optional[dict[str, Union[dict[str, PathItem], Reference, Any]]] = None + pathItems: Optional[dict[str, Union[PathItem, Reference]]] = None class Tag(BaseModelWithConfig): @@ -436,13 +437,13 @@ class OpenAPI(BaseModelWithConfig): openapi: str info: Info jsonSchemaDialect: Optional[str] = None - servers: Optional[List[Server]] = None + servers: Optional[list[Server]] = None # Using Any for Specification Extensions - paths: Optional[Dict[str, Union[PathItem, Any]]] = None - webhooks: Optional[Dict[str, Union[PathItem, Reference]]] = None + paths: Optional[dict[str, Union[PathItem, Any]]] = None + webhooks: Optional[dict[str, Union[PathItem, Reference]]] = None components: Optional[Components] = None - security: Optional[List[Dict[str, List[str]]]] = None - tags: Optional[List[Tag]] = None + security: Optional[list[dict[str, list[str]]]] = None + tags: Optional[list[Tag]] = None externalDocs: Optional[ExternalDocumentation] = None diff --git a/fastapi/openapi/utils.py b/fastapi/openapi/utils.py index 9fe2044f26..a99d4188e7 100644 --- a/fastapi/openapi/utils.py +++ b/fastapi/openapi/utils.py @@ -1,7 +1,8 @@ import http.client import inspect import warnings -from typing import Any, Dict, List, Optional, Sequence, Set, Tuple, Type, Union, cast +from collections.abc import Sequence +from typing import Any, Optional, Union, cast from fastapi import routing from fastapi._compat import ( @@ -66,7 +67,7 @@ validation_error_response_definition = { }, } -status_code_ranges: Dict[str, str] = { +status_code_ranges: dict[str, str] = { "1XX": "Information", "2XX": "Success", "3XX": "Redirection", @@ -78,10 +79,10 @@ status_code_ranges: Dict[str, str] = { def get_openapi_security_definitions( flat_dependant: Dependant, -) -> Tuple[Dict[str, Any], List[Dict[str, Any]]]: +) -> tuple[dict[str, Any], list[dict[str, Any]]]: security_definitions = {} # Use a dict to merge scopes for same security scheme - operation_security_dict: Dict[str, List[str]] = {} + operation_security_dict: dict[str, list[str]] = {} for security_dependency in flat_dependant._security_dependencies: security_definition = jsonable_encoder( security_dependency._security_scheme.model, @@ -106,11 +107,11 @@ def _get_openapi_operation_parameters( *, dependant: Dependant, model_name_map: ModelNameMap, - field_mapping: Dict[ - Tuple[ModelField, Literal["validation", "serialization"]], JsonSchemaValue + field_mapping: dict[ + tuple[ModelField, Literal["validation", "serialization"]], JsonSchemaValue ], separate_input_output_schemas: bool = True, -) -> List[Dict[str, Any]]: +) -> list[dict[str, Any]]: parameters = [] flat_dependant = get_flat_dependant(dependant, skip_repeats=True) path_params = _get_flat_fields_from_params(flat_dependant.path_params) @@ -179,11 +180,11 @@ def get_openapi_operation_request_body( *, body_field: Optional[ModelField], model_name_map: ModelNameMap, - field_mapping: Dict[ - Tuple[ModelField, Literal["validation", "serialization"]], JsonSchemaValue + field_mapping: dict[ + tuple[ModelField, Literal["validation", "serialization"]], JsonSchemaValue ], separate_input_output_schemas: bool = True, -) -> Optional[Dict[str, Any]]: +) -> Optional[dict[str, Any]]: if not body_field: return None assert _is_model_field(body_field) @@ -196,10 +197,10 @@ def get_openapi_operation_request_body( field_info = cast(Body, body_field.field_info) request_media_type = field_info.media_type required = body_field.required - request_body_oai: Dict[str, Any] = {} + request_body_oai: dict[str, Any] = {} if required: request_body_oai["required"] = required - request_media_content: Dict[str, Any] = {"schema": body_schema} + request_media_content: dict[str, Any] = {"schema": body_schema} if field_info.openapi_examples: request_media_content["examples"] = jsonable_encoder( field_info.openapi_examples @@ -232,9 +233,9 @@ def generate_operation_summary(*, route: routing.APIRoute, method: str) -> str: def get_openapi_operation_metadata( - *, route: routing.APIRoute, method: str, operation_ids: Set[str] -) -> Dict[str, Any]: - operation: Dict[str, Any] = {} + *, route: routing.APIRoute, method: str, operation_ids: set[str] +) -> dict[str, Any]: + operation: dict[str, Any] = {} if route.tags: operation["tags"] = route.tags operation["summary"] = generate_operation_summary(route=route, method=method) @@ -260,19 +261,19 @@ def get_openapi_operation_metadata( def get_openapi_path( *, route: routing.APIRoute, - operation_ids: Set[str], + operation_ids: set[str], model_name_map: ModelNameMap, - field_mapping: Dict[ - Tuple[ModelField, Literal["validation", "serialization"]], JsonSchemaValue + field_mapping: dict[ + tuple[ModelField, Literal["validation", "serialization"]], JsonSchemaValue ], separate_input_output_schemas: bool = True, -) -> Tuple[Dict[str, Any], Dict[str, Any], Dict[str, Any]]: +) -> tuple[dict[str, Any], dict[str, Any], dict[str, Any]]: path = {} - security_schemes: Dict[str, Any] = {} - definitions: Dict[str, Any] = {} + security_schemes: dict[str, Any] = {} + definitions: dict[str, Any] = {} assert route.methods is not None, "Methods must be a list" if isinstance(route.response_class, DefaultPlaceholder): - current_response_class: Type[Response] = route.response_class.value + current_response_class: type[Response] = route.response_class.value else: current_response_class = route.response_class assert current_response_class, "A response class is needed to generate OpenAPI" @@ -282,7 +283,7 @@ def get_openapi_path( operation = get_openapi_operation_metadata( route=route, method=method, operation_ids=operation_ids ) - parameters: List[Dict[str, Any]] = [] + parameters: list[dict[str, Any]] = [] flat_dependant = get_flat_dependant(route.dependant, skip_repeats=True) security_definitions, operation_security = get_openapi_security_definitions( flat_dependant=flat_dependant @@ -390,7 +391,7 @@ def get_openapi_path( "An additional response must be a dict" ) field = route.response_fields.get(additional_status_code) - additional_field_schema: Optional[Dict[str, Any]] = None + additional_field_schema: Optional[dict[str, Any]] = None if field: additional_field_schema = get_schema_from_model_field( field=field, @@ -445,11 +446,11 @@ def get_openapi_path( def get_fields_from_routes( routes: Sequence[BaseRoute], -) -> List[ModelField]: - body_fields_from_routes: List[ModelField] = [] - responses_from_routes: List[ModelField] = [] - request_fields_from_routes: List[ModelField] = [] - callback_flat_models: List[ModelField] = [] +) -> list[ModelField]: + body_fields_from_routes: list[ModelField] = [] + responses_from_routes: list[ModelField] = [] + request_fields_from_routes: list[ModelField] = [] + callback_flat_models: list[ModelField] = [] for route in routes: if getattr(route, "include_in_schema", None) and isinstance( route, routing.APIRoute @@ -483,15 +484,15 @@ def get_openapi( description: Optional[str] = None, routes: Sequence[BaseRoute], webhooks: Optional[Sequence[BaseRoute]] = None, - tags: Optional[List[Dict[str, Any]]] = None, - servers: Optional[List[Dict[str, Union[str, Any]]]] = None, + tags: Optional[list[dict[str, Any]]] = None, + servers: Optional[list[dict[str, Union[str, Any]]]] = None, terms_of_service: Optional[str] = None, - contact: Optional[Dict[str, Union[str, Any]]] = None, - license_info: Optional[Dict[str, Union[str, Any]]] = None, + contact: Optional[dict[str, Union[str, Any]]] = None, + license_info: Optional[dict[str, Union[str, Any]]] = None, separate_input_output_schemas: bool = True, - external_docs: Optional[Dict[str, Any]] = None, -) -> Dict[str, Any]: - info: Dict[str, Any] = {"title": title, "version": version} + external_docs: Optional[dict[str, Any]] = None, +) -> dict[str, Any]: + info: dict[str, Any] = {"title": title, "version": version} if summary: info["summary"] = summary if description: @@ -502,13 +503,13 @@ def get_openapi( info["contact"] = contact if license_info: info["license"] = license_info - output: Dict[str, Any] = {"openapi": openapi_version, "info": info} + output: dict[str, Any] = {"openapi": openapi_version, "info": info} if servers: output["servers"] = servers - components: Dict[str, Dict[str, Any]] = {} - paths: Dict[str, Dict[str, Any]] = {} - webhook_paths: Dict[str, Dict[str, Any]] = {} - operation_ids: Set[str] = set() + components: dict[str, dict[str, Any]] = {} + paths: dict[str, dict[str, Any]] = {} + webhook_paths: dict[str, dict[str, Any]] = {} + operation_ids: set[str] = set() all_fields = get_fields_from_routes(list(routes or []) + list(webhooks or [])) model_name_map = get_compat_model_name_map(all_fields) field_mapping, definitions = get_definitions( diff --git a/fastapi/param_functions.py b/fastapi/param_functions.py index e32f755933..844542594b 100644 --- a/fastapi/param_functions.py +++ b/fastapi/param_functions.py @@ -1,10 +1,11 @@ -from typing import Any, Callable, Dict, List, Optional, Sequence, Union +from collections.abc import Sequence +from typing import Annotated, Any, Callable, Optional, 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, Literal, deprecated +from typing_extensions import Literal, deprecated _Unset: Any = Undefined @@ -209,7 +210,7 @@ def Path( # noqa: N802 ), ] = _Unset, examples: Annotated[ - Optional[List[Any]], + Optional[list[Any]], Doc( """ Example values for this field. @@ -224,7 +225,7 @@ def Path( # noqa: N802 ), ] = _Unset, openapi_examples: Annotated[ - Optional[Dict[str, Example]], + Optional[dict[str, Example]], Doc( """ OpenAPI-specific examples. @@ -262,7 +263,7 @@ def Path( # noqa: N802 ), ] = True, json_schema_extra: Annotated[ - Union[Dict[str, Any], None], + Union[dict[str, Any], None], Doc( """ Any additional JSON schema data. @@ -534,7 +535,7 @@ def Query( # noqa: N802 ), ] = _Unset, examples: Annotated[ - Optional[List[Any]], + Optional[list[Any]], Doc( """ Example values for this field. @@ -549,7 +550,7 @@ def Query( # noqa: N802 ), ] = _Unset, openapi_examples: Annotated[ - Optional[Dict[str, Example]], + Optional[dict[str, Example]], Doc( """ OpenAPI-specific examples. @@ -587,7 +588,7 @@ def Query( # noqa: N802 ), ] = True, json_schema_extra: Annotated[ - Union[Dict[str, Any], None], + Union[dict[str, Any], None], Doc( """ Any additional JSON schema data. @@ -849,7 +850,7 @@ def Header( # noqa: N802 ), ] = _Unset, examples: Annotated[ - Optional[List[Any]], + Optional[list[Any]], Doc( """ Example values for this field. @@ -864,7 +865,7 @@ def Header( # noqa: N802 ), ] = _Unset, openapi_examples: Annotated[ - Optional[Dict[str, Example]], + Optional[dict[str, Example]], Doc( """ OpenAPI-specific examples. @@ -902,7 +903,7 @@ def Header( # noqa: N802 ), ] = True, json_schema_extra: Annotated[ - Union[Dict[str, Any], None], + Union[dict[str, Any], None], Doc( """ Any additional JSON schema data. @@ -1154,7 +1155,7 @@ def Cookie( # noqa: N802 ), ] = _Unset, examples: Annotated[ - Optional[List[Any]], + Optional[list[Any]], Doc( """ Example values for this field. @@ -1169,7 +1170,7 @@ def Cookie( # noqa: N802 ), ] = _Unset, openapi_examples: Annotated[ - Optional[Dict[str, Example]], + Optional[dict[str, Example]], Doc( """ OpenAPI-specific examples. @@ -1207,7 +1208,7 @@ def Cookie( # noqa: N802 ), ] = True, json_schema_extra: Annotated[ - Union[Dict[str, Any], None], + Union[dict[str, Any], None], Doc( """ Any additional JSON schema data. @@ -1481,7 +1482,7 @@ def Body( # noqa: N802 ), ] = _Unset, examples: Annotated[ - Optional[List[Any]], + Optional[list[Any]], Doc( """ Example values for this field. @@ -1496,7 +1497,7 @@ def Body( # noqa: N802 ), ] = _Unset, openapi_examples: Annotated[ - Optional[Dict[str, Example]], + Optional[dict[str, Example]], Doc( """ OpenAPI-specific examples. @@ -1534,7 +1535,7 @@ def Body( # noqa: N802 ), ] = True, json_schema_extra: Annotated[ - Union[Dict[str, Any], None], + Union[dict[str, Any], None], Doc( """ Any additional JSON schema data. @@ -1796,7 +1797,7 @@ def Form( # noqa: N802 ), ] = _Unset, examples: Annotated[ - Optional[List[Any]], + Optional[list[Any]], Doc( """ Example values for this field. @@ -1811,7 +1812,7 @@ def Form( # noqa: N802 ), ] = _Unset, openapi_examples: Annotated[ - Optional[Dict[str, Example]], + Optional[dict[str, Example]], Doc( """ OpenAPI-specific examples. @@ -1849,7 +1850,7 @@ def Form( # noqa: N802 ), ] = True, json_schema_extra: Annotated[ - Union[Dict[str, Any], None], + Union[dict[str, Any], None], Doc( """ Any additional JSON schema data. @@ -2110,7 +2111,7 @@ def File( # noqa: N802 ), ] = _Unset, examples: Annotated[ - Optional[List[Any]], + Optional[list[Any]], Doc( """ Example values for this field. @@ -2125,7 +2126,7 @@ def File( # noqa: N802 ), ] = _Unset, openapi_examples: Annotated[ - Optional[Dict[str, Example]], + Optional[dict[str, Example]], Doc( """ OpenAPI-specific examples. @@ -2163,7 +2164,7 @@ def File( # noqa: N802 ), ] = True, json_schema_extra: Annotated[ - Union[Dict[str, Any], None], + Union[dict[str, Any], None], Doc( """ Any additional JSON schema data. diff --git a/fastapi/params.py b/fastapi/params.py index b6d0f08e31..4990d0e70e 100644 --- a/fastapi/params.py +++ b/fastapi/params.py @@ -1,11 +1,12 @@ import warnings +from collections.abc import Sequence from dataclasses import dataclass from enum import Enum -from typing import Any, Callable, Dict, List, Optional, Sequence, Union +from typing import Annotated, Any, Callable, Optional, Union from fastapi.openapi.models import Example from pydantic.fields import FieldInfo -from typing_extensions import Annotated, Literal, deprecated +from typing_extensions import Literal, deprecated from ._compat import ( PYDANTIC_V2, @@ -59,7 +60,7 @@ class Param(FieldInfo): # type: ignore[misc] allow_inf_nan: Union[bool, None] = _Unset, max_digits: Union[int, None] = _Unset, decimal_places: Union[int, None] = _Unset, - examples: Optional[List[Any]] = None, + examples: Optional[list[Any]] = None, example: Annotated[ Optional[Any], deprecated( @@ -67,10 +68,10 @@ class Param(FieldInfo): # type: ignore[misc] "although still supported. Use examples instead." ), ] = _Unset, - openapi_examples: Optional[Dict[str, Example]] = None, + openapi_examples: Optional[dict[str, Example]] = None, deprecated: Union[deprecated, str, bool, None] = None, include_in_schema: bool = True, - json_schema_extra: Union[Dict[str, Any], None] = None, + json_schema_extra: Union[dict[str, Any], None] = None, **extra: Any, ): if example is not _Unset: @@ -177,7 +178,7 @@ class Path(Param): # type: ignore[misc] allow_inf_nan: Union[bool, None] = _Unset, max_digits: Union[int, None] = _Unset, decimal_places: Union[int, None] = _Unset, - examples: Optional[List[Any]] = None, + examples: Optional[list[Any]] = None, example: Annotated[ Optional[Any], deprecated( @@ -185,10 +186,10 @@ class Path(Param): # type: ignore[misc] "although still supported. Use examples instead." ), ] = _Unset, - openapi_examples: Optional[Dict[str, Example]] = None, + openapi_examples: Optional[dict[str, Example]] = None, deprecated: Union[deprecated, str, bool, None] = None, include_in_schema: bool = True, - json_schema_extra: Union[Dict[str, Any], None] = None, + json_schema_extra: Union[dict[str, Any], None] = None, **extra: Any, ): assert default is ..., "Path parameters cannot have a default value" @@ -263,7 +264,7 @@ class Query(Param): # type: ignore[misc] allow_inf_nan: Union[bool, None] = _Unset, max_digits: Union[int, None] = _Unset, decimal_places: Union[int, None] = _Unset, - examples: Optional[List[Any]] = None, + examples: Optional[list[Any]] = None, example: Annotated[ Optional[Any], deprecated( @@ -271,10 +272,10 @@ class Query(Param): # type: ignore[misc] "although still supported. Use examples instead." ), ] = _Unset, - openapi_examples: Optional[Dict[str, Example]] = None, + openapi_examples: Optional[dict[str, Example]] = None, deprecated: Union[deprecated, str, bool, None] = None, include_in_schema: bool = True, - json_schema_extra: Union[Dict[str, Any], None] = None, + json_schema_extra: Union[dict[str, Any], None] = None, **extra: Any, ): super().__init__( @@ -348,7 +349,7 @@ class Header(Param): # type: ignore[misc] allow_inf_nan: Union[bool, None] = _Unset, max_digits: Union[int, None] = _Unset, decimal_places: Union[int, None] = _Unset, - examples: Optional[List[Any]] = None, + examples: Optional[list[Any]] = None, example: Annotated[ Optional[Any], deprecated( @@ -356,10 +357,10 @@ class Header(Param): # type: ignore[misc] "although still supported. Use examples instead." ), ] = _Unset, - openapi_examples: Optional[Dict[str, Example]] = None, + openapi_examples: Optional[dict[str, Example]] = None, deprecated: Union[deprecated, str, bool, None] = None, include_in_schema: bool = True, - json_schema_extra: Union[Dict[str, Any], None] = None, + json_schema_extra: Union[dict[str, Any], None] = None, **extra: Any, ): self.convert_underscores = convert_underscores @@ -433,7 +434,7 @@ class Cookie(Param): # type: ignore[misc] allow_inf_nan: Union[bool, None] = _Unset, max_digits: Union[int, None] = _Unset, decimal_places: Union[int, None] = _Unset, - examples: Optional[List[Any]] = None, + examples: Optional[list[Any]] = None, example: Annotated[ Optional[Any], deprecated( @@ -441,10 +442,10 @@ class Cookie(Param): # type: ignore[misc] "although still supported. Use examples instead." ), ] = _Unset, - openapi_examples: Optional[Dict[str, Example]] = None, + openapi_examples: Optional[dict[str, Example]] = None, deprecated: Union[deprecated, str, bool, None] = None, include_in_schema: bool = True, - json_schema_extra: Union[Dict[str, Any], None] = None, + json_schema_extra: Union[dict[str, Any], None] = None, **extra: Any, ): super().__init__( @@ -517,7 +518,7 @@ class Body(FieldInfo): # type: ignore[misc] allow_inf_nan: Union[bool, None] = _Unset, max_digits: Union[int, None] = _Unset, decimal_places: Union[int, None] = _Unset, - examples: Optional[List[Any]] = None, + examples: Optional[list[Any]] = None, example: Annotated[ Optional[Any], deprecated( @@ -525,10 +526,10 @@ class Body(FieldInfo): # type: ignore[misc] "although still supported. Use examples instead." ), ] = _Unset, - openapi_examples: Optional[Dict[str, Example]] = None, + openapi_examples: Optional[dict[str, Example]] = None, deprecated: Union[deprecated, str, bool, None] = None, include_in_schema: bool = True, - json_schema_extra: Union[Dict[str, Any], None] = None, + json_schema_extra: Union[dict[str, Any], None] = None, **extra: Any, ): self.embed = embed @@ -637,7 +638,7 @@ class Form(Body): # type: ignore[misc] allow_inf_nan: Union[bool, None] = _Unset, max_digits: Union[int, None] = _Unset, decimal_places: Union[int, None] = _Unset, - examples: Optional[List[Any]] = None, + examples: Optional[list[Any]] = None, example: Annotated[ Optional[Any], deprecated( @@ -645,10 +646,10 @@ class Form(Body): # type: ignore[misc] "although still supported. Use examples instead." ), ] = _Unset, - openapi_examples: Optional[Dict[str, Example]] = None, + openapi_examples: Optional[dict[str, Example]] = None, deprecated: Union[deprecated, str, bool, None] = None, include_in_schema: bool = True, - json_schema_extra: Union[Dict[str, Any], None] = None, + json_schema_extra: Union[dict[str, Any], None] = None, **extra: Any, ): super().__init__( @@ -721,7 +722,7 @@ class File(Form): # type: ignore[misc] allow_inf_nan: Union[bool, None] = _Unset, max_digits: Union[int, None] = _Unset, decimal_places: Union[int, None] = _Unset, - examples: Optional[List[Any]] = None, + examples: Optional[list[Any]] = None, example: Annotated[ Optional[Any], deprecated( @@ -729,10 +730,10 @@ class File(Form): # type: ignore[misc] "although still supported. Use examples instead." ), ] = _Unset, - openapi_examples: Optional[Dict[str, Example]] = None, + openapi_examples: Optional[dict[str, Example]] = None, deprecated: Union[deprecated, str, bool, None] = None, include_in_schema: bool = True, - json_schema_extra: Union[Dict[str, Any], None] = None, + json_schema_extra: Union[dict[str, Any], None] = None, **extra: Any, ): super().__init__( diff --git a/fastapi/routing.py b/fastapi/routing.py index 9be2b44bc1..fa6904a6b6 100644 --- a/fastapi/routing.py +++ b/fastapi/routing.py @@ -3,23 +3,21 @@ import email.message import functools import inspect import json +from collections.abc import ( + AsyncIterator, + Awaitable, + Collection, + Coroutine, + Mapping, + Sequence, +) from contextlib import AsyncExitStack, asynccontextmanager from enum import Enum, IntEnum from typing import ( + Annotated, Any, - AsyncIterator, - Awaitable, Callable, - Collection, - Coroutine, - Dict, - List, - Mapping, Optional, - Sequence, - Set, - Tuple, - Type, Union, ) @@ -77,7 +75,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, deprecated +from typing_extensions import deprecated # Copy of starlette.routing.request_response modified to include the @@ -214,7 +212,7 @@ def _merge_lifespan_context( # Cache for endpoint context to avoid re-extracting on every request -_endpoint_context_cache: Dict[int, EndpointContext] = {} +_endpoint_context_cache: dict[int, EndpointContext] = {} def _extract_endpoint_context(func: Any) -> EndpointContext: @@ -306,7 +304,7 @@ async def serialize_response( async def run_endpoint_function( - *, dependant: Dependant, values: Dict[str, Any], is_coroutine: bool + *, dependant: Dependant, values: dict[str, Any], is_coroutine: bool ) -> Any: # Only called by get_request_handler. Has been split into its own function to # facilitate profiling endpoints, since inner functions are harder to profile. @@ -322,7 +320,7 @@ def get_request_handler( dependant: Dependant, body_field: Optional[ModelField] = None, status_code: Optional[int] = None, - response_class: Union[Type[Response], DefaultPlaceholder] = Default(JSONResponse), + response_class: Union[type[Response], DefaultPlaceholder] = Default(JSONResponse), response_field: Optional[ModelField] = None, response_model_include: Optional[IncEx] = None, response_model_exclude: Optional[IncEx] = None, @@ -339,7 +337,7 @@ def get_request_handler( body_field.field_info, (params.Form, temp_pydantic_v1_params.Form) ) if isinstance(response_class, DefaultPlaceholder): - actual_response_class: Type[Response] = response_class.value + actual_response_class: type[Response] = response_class.value else: actual_response_class = response_class @@ -412,7 +410,7 @@ def get_request_handler( raise http_error from e # Solve dependencies and run path operation function, auto-closing dependencies - errors: List[Any] = [] + errors: list[Any] = [] async_exit_stack = request.scope.get("fastapi_inner_astack") assert isinstance(async_exit_stack, AsyncExitStack), ( "fastapi_inner_astack not found in request scope" @@ -437,7 +435,7 @@ def get_request_handler( raw_response.background = solved_result.background_tasks response = raw_response else: - response_args: Dict[str, Any] = { + response_args: dict[str, Any] = { "background": solved_result.background_tasks } # If status_code was set, use it, otherwise use the default from the @@ -550,7 +548,7 @@ class APIWebSocketRoute(routing.WebSocketRoute): ) ) - def matches(self, scope: Scope) -> Tuple[Match, Scope]: + def matches(self, scope: Scope) -> tuple[Match, Scope]: match, child_scope = super().matches(scope) if match != Match.NONE: child_scope["route"] = self @@ -565,15 +563,15 @@ class APIRoute(routing.Route): *, response_model: Any = Default(None), status_code: Optional[int] = None, - tags: Optional[List[Union[str, Enum]]] = None, + tags: Optional[list[Union[str, Enum]]] = None, dependencies: Optional[Sequence[params.Depends]] = None, summary: Optional[str] = None, description: Optional[str] = None, response_description: str = "Successful Response", - responses: Optional[Dict[Union[int, str], Dict[str, Any]]] = None, + responses: Optional[dict[Union[int, str], dict[str, Any]]] = None, deprecated: Optional[bool] = None, name: Optional[str] = None, - methods: Optional[Union[Set[str], List[str]]] = None, + methods: Optional[Union[set[str], list[str]]] = None, operation_id: Optional[str] = None, response_model_include: Optional[IncEx] = None, response_model_exclude: Optional[IncEx] = None, @@ -582,12 +580,12 @@ class APIRoute(routing.Route): response_model_exclude_defaults: bool = False, response_model_exclude_none: bool = False, include_in_schema: bool = True, - response_class: Union[Type[Response], DefaultPlaceholder] = Default( + response_class: Union[type[Response], DefaultPlaceholder] = Default( JSONResponse ), dependency_overrides_provider: Optional[Any] = None, - callbacks: Optional[List[BaseRoute]] = None, - openapi_extra: Optional[Dict[str, Any]] = None, + callbacks: Optional[list[BaseRoute]] = None, + openapi_extra: Optional[dict[str, Any]] = None, generate_unique_id_function: Union[ Callable[["APIRoute"], str], DefaultPlaceholder ] = Default(generate_unique_id), @@ -623,7 +621,7 @@ class APIRoute(routing.Route): self.path_regex, self.path_format, self.param_convertors = compile_path(path) if methods is None: methods = ["GET"] - self.methods: Set[str] = {method.upper() for method in methods} + self.methods: set[str] = {method.upper() for method in methods} if isinstance(generate_unique_id_function, DefaultPlaceholder): current_generate_unique_id: Callable[[APIRoute], str] = ( generate_unique_id_function.value @@ -678,7 +676,7 @@ class APIRoute(routing.Route): ) response_fields[additional_status_code] = response_field if response_fields: - self.response_fields: Dict[Union[int, str], ModelField] = response_fields + self.response_fields: dict[Union[int, str], ModelField] = response_fields else: self.response_fields = {} @@ -719,7 +717,7 @@ class APIRoute(routing.Route): embed_body_fields=self._embed_body_fields, ) - def matches(self, scope: Scope) -> Tuple[Match, Scope]: + def matches(self, scope: Scope) -> tuple[Match, Scope]: match, child_scope = super().matches(scope) if match != Match.NONE: child_scope["route"] = self @@ -758,7 +756,7 @@ class APIRouter(routing.Router): *, prefix: Annotated[str, Doc("An optional path prefix for the router.")] = "", tags: Annotated[ - Optional[List[Union[str, Enum]]], + Optional[list[Union[str, Enum]]], Doc( """ A list of tags to be applied to all the *path operations* in this @@ -784,7 +782,7 @@ class APIRouter(routing.Router): ), ] = None, default_response_class: Annotated[ - Type[Response], + type[Response], Doc( """ The default response class to be used. @@ -795,7 +793,7 @@ class APIRouter(routing.Router): ), ] = Default(JSONResponse), responses: Annotated[ - Optional[Dict[Union[int, str], Dict[str, Any]]], + Optional[dict[Union[int, str], dict[str, Any]]], Doc( """ Additional responses to be shown in OpenAPI. @@ -811,7 +809,7 @@ class APIRouter(routing.Router): ), ] = None, callbacks: Annotated[ - Optional[List[BaseRoute]], + Optional[list[BaseRoute]], Doc( """ OpenAPI callbacks that should apply to all *path operations* in this @@ -825,7 +823,7 @@ class APIRouter(routing.Router): ), ] = None, routes: Annotated[ - Optional[List[BaseRoute]], + Optional[list[BaseRoute]], Doc( """ **Note**: you probably shouldn't use this parameter, it is inherited @@ -876,7 +874,7 @@ class APIRouter(routing.Router): ), ] = None, route_class: Annotated[ - Type[APIRoute], + type[APIRoute], Doc( """ Custom route (*path operation*) class to be used by this router. @@ -982,7 +980,7 @@ class APIRouter(routing.Router): "A path prefix must not end with '/', as the routes will start with '/'" ) self.prefix = prefix - self.tags: List[Union[str, Enum]] = tags or [] + self.tags: list[Union[str, Enum]] = tags or [] self.dependencies = list(dependencies or []) self.deprecated = deprecated self.include_in_schema = include_in_schema @@ -1019,14 +1017,14 @@ class APIRouter(routing.Router): *, response_model: Any = Default(None), status_code: Optional[int] = None, - tags: Optional[List[Union[str, Enum]]] = None, + tags: Optional[list[Union[str, Enum]]] = None, dependencies: Optional[Sequence[params.Depends]] = None, summary: Optional[str] = None, description: Optional[str] = None, response_description: str = "Successful Response", - responses: Optional[Dict[Union[int, str], Dict[str, Any]]] = None, + responses: Optional[dict[Union[int, str], dict[str, Any]]] = None, deprecated: Optional[bool] = None, - methods: Optional[Union[Set[str], List[str]]] = None, + methods: Optional[Union[set[str], list[str]]] = None, operation_id: Optional[str] = None, response_model_include: Optional[IncEx] = None, response_model_exclude: Optional[IncEx] = None, @@ -1035,13 +1033,13 @@ class APIRouter(routing.Router): response_model_exclude_defaults: bool = False, response_model_exclude_none: bool = False, include_in_schema: bool = True, - response_class: Union[Type[Response], DefaultPlaceholder] = Default( + response_class: Union[type[Response], DefaultPlaceholder] = Default( JSONResponse ), name: Optional[str] = None, - route_class_override: Optional[Type[APIRoute]] = None, - callbacks: Optional[List[BaseRoute]] = None, - openapi_extra: Optional[Dict[str, Any]] = None, + route_class_override: Optional[type[APIRoute]] = None, + callbacks: Optional[list[BaseRoute]] = None, + openapi_extra: Optional[dict[str, Any]] = None, generate_unique_id_function: Union[ Callable[[APIRoute], str], DefaultPlaceholder ] = Default(generate_unique_id), @@ -1100,14 +1098,14 @@ class APIRouter(routing.Router): *, response_model: Any = Default(None), status_code: Optional[int] = None, - tags: Optional[List[Union[str, Enum]]] = None, + tags: Optional[list[Union[str, Enum]]] = None, dependencies: Optional[Sequence[params.Depends]] = None, summary: Optional[str] = None, description: Optional[str] = None, response_description: str = "Successful Response", - responses: Optional[Dict[Union[int, str], Dict[str, Any]]] = None, + responses: Optional[dict[Union[int, str], dict[str, Any]]] = None, deprecated: Optional[bool] = None, - methods: Optional[List[str]] = None, + methods: Optional[list[str]] = None, operation_id: Optional[str] = None, response_model_include: Optional[IncEx] = None, response_model_exclude: Optional[IncEx] = None, @@ -1116,10 +1114,10 @@ class APIRouter(routing.Router): response_model_exclude_defaults: bool = False, response_model_exclude_none: bool = False, include_in_schema: bool = True, - response_class: Type[Response] = Default(JSONResponse), + response_class: type[Response] = Default(JSONResponse), name: Optional[str] = None, - callbacks: Optional[List[BaseRoute]] = None, - openapi_extra: Optional[Dict[str, Any]] = None, + callbacks: Optional[list[BaseRoute]] = None, + openapi_extra: Optional[dict[str, Any]] = None, generate_unique_id_function: Callable[[APIRoute], str] = Default( generate_unique_id ), @@ -1259,7 +1257,7 @@ class APIRouter(routing.Router): *, prefix: Annotated[str, Doc("An optional path prefix for the router.")] = "", tags: Annotated[ - Optional[List[Union[str, Enum]]], + Optional[list[Union[str, Enum]]], Doc( """ A list of tags to be applied to all the *path operations* in this @@ -1285,7 +1283,7 @@ class APIRouter(routing.Router): ), ] = None, default_response_class: Annotated[ - Type[Response], + type[Response], Doc( """ The default response class to be used. @@ -1296,7 +1294,7 @@ class APIRouter(routing.Router): ), ] = Default(JSONResponse), responses: Annotated[ - Optional[Dict[Union[int, str], Dict[str, Any]]], + Optional[dict[Union[int, str], dict[str, Any]]], Doc( """ Additional responses to be shown in OpenAPI. @@ -1312,7 +1310,7 @@ class APIRouter(routing.Router): ), ] = None, callbacks: Annotated[ - Optional[List[BaseRoute]], + Optional[list[BaseRoute]], Doc( """ OpenAPI callbacks that should apply to all *path operations* in this @@ -1417,7 +1415,7 @@ class APIRouter(routing.Router): current_tags.extend(tags) if route.tags: current_tags.extend(route.tags) - current_dependencies: List[params.Depends] = [] + current_dependencies: list[params.Depends] = [] if dependencies: current_dependencies.extend(dependencies) if route.dependencies: @@ -1558,7 +1556,7 @@ class APIRouter(routing.Router): ), ] = None, tags: Annotated[ - Optional[List[Union[str, Enum]]], + Optional[list[Union[str, Enum]]], Doc( """ A list of tags to be applied to the *path operation*. @@ -1624,7 +1622,7 @@ class APIRouter(routing.Router): ), ] = "Successful Response", responses: Annotated[ - Optional[Dict[Union[int, str], Dict[str, Any]]], + Optional[dict[Union[int, str], dict[str, Any]]], Doc( """ Additional responses that could be returned by this *path operation*. @@ -1765,7 +1763,7 @@ class APIRouter(routing.Router): ), ] = True, response_class: Annotated[ - Type[Response], + type[Response], Doc( """ Response class to be used for this *path operation*. @@ -1786,7 +1784,7 @@ class APIRouter(routing.Router): ), ] = None, callbacks: Annotated[ - Optional[List[BaseRoute]], + Optional[list[BaseRoute]], Doc( """ List of *path operations* that will be used as OpenAPI callbacks. @@ -1802,7 +1800,7 @@ class APIRouter(routing.Router): ), ] = None, openapi_extra: Annotated[ - Optional[Dict[str, Any]], + Optional[dict[str, Any]], Doc( """ Extra metadata to be included in the OpenAPI schema for this *path @@ -1935,7 +1933,7 @@ class APIRouter(routing.Router): ), ] = None, tags: Annotated[ - Optional[List[Union[str, Enum]]], + Optional[list[Union[str, Enum]]], Doc( """ A list of tags to be applied to the *path operation*. @@ -2001,7 +1999,7 @@ class APIRouter(routing.Router): ), ] = "Successful Response", responses: Annotated[ - Optional[Dict[Union[int, str], Dict[str, Any]]], + Optional[dict[Union[int, str], dict[str, Any]]], Doc( """ Additional responses that could be returned by this *path operation*. @@ -2142,7 +2140,7 @@ class APIRouter(routing.Router): ), ] = True, response_class: Annotated[ - Type[Response], + type[Response], Doc( """ Response class to be used for this *path operation*. @@ -2163,7 +2161,7 @@ class APIRouter(routing.Router): ), ] = None, callbacks: Annotated[ - Optional[List[BaseRoute]], + Optional[list[BaseRoute]], Doc( """ List of *path operations* that will be used as OpenAPI callbacks. @@ -2179,7 +2177,7 @@ class APIRouter(routing.Router): ), ] = None, openapi_extra: Annotated[ - Optional[Dict[str, Any]], + Optional[dict[str, Any]], Doc( """ Extra metadata to be included in the OpenAPI schema for this *path @@ -2317,7 +2315,7 @@ class APIRouter(routing.Router): ), ] = None, tags: Annotated[ - Optional[List[Union[str, Enum]]], + Optional[list[Union[str, Enum]]], Doc( """ A list of tags to be applied to the *path operation*. @@ -2383,7 +2381,7 @@ class APIRouter(routing.Router): ), ] = "Successful Response", responses: Annotated[ - Optional[Dict[Union[int, str], Dict[str, Any]]], + Optional[dict[Union[int, str], dict[str, Any]]], Doc( """ Additional responses that could be returned by this *path operation*. @@ -2524,7 +2522,7 @@ class APIRouter(routing.Router): ), ] = True, response_class: Annotated[ - Type[Response], + type[Response], Doc( """ Response class to be used for this *path operation*. @@ -2545,7 +2543,7 @@ class APIRouter(routing.Router): ), ] = None, callbacks: Annotated[ - Optional[List[BaseRoute]], + Optional[list[BaseRoute]], Doc( """ List of *path operations* that will be used as OpenAPI callbacks. @@ -2561,7 +2559,7 @@ class APIRouter(routing.Router): ), ] = None, openapi_extra: Annotated[ - Optional[Dict[str, Any]], + Optional[dict[str, Any]], Doc( """ Extra metadata to be included in the OpenAPI schema for this *path @@ -2699,7 +2697,7 @@ class APIRouter(routing.Router): ), ] = None, tags: Annotated[ - Optional[List[Union[str, Enum]]], + Optional[list[Union[str, Enum]]], Doc( """ A list of tags to be applied to the *path operation*. @@ -2765,7 +2763,7 @@ class APIRouter(routing.Router): ), ] = "Successful Response", responses: Annotated[ - Optional[Dict[Union[int, str], Dict[str, Any]]], + Optional[dict[Union[int, str], dict[str, Any]]], Doc( """ Additional responses that could be returned by this *path operation*. @@ -2906,7 +2904,7 @@ class APIRouter(routing.Router): ), ] = True, response_class: Annotated[ - Type[Response], + type[Response], Doc( """ Response class to be used for this *path operation*. @@ -2927,7 +2925,7 @@ class APIRouter(routing.Router): ), ] = None, callbacks: Annotated[ - Optional[List[BaseRoute]], + Optional[list[BaseRoute]], Doc( """ List of *path operations* that will be used as OpenAPI callbacks. @@ -2943,7 +2941,7 @@ class APIRouter(routing.Router): ), ] = None, openapi_extra: Annotated[ - Optional[Dict[str, Any]], + Optional[dict[str, Any]], Doc( """ Extra metadata to be included in the OpenAPI schema for this *path @@ -3076,7 +3074,7 @@ class APIRouter(routing.Router): ), ] = None, tags: Annotated[ - Optional[List[Union[str, Enum]]], + Optional[list[Union[str, Enum]]], Doc( """ A list of tags to be applied to the *path operation*. @@ -3142,7 +3140,7 @@ class APIRouter(routing.Router): ), ] = "Successful Response", responses: Annotated[ - Optional[Dict[Union[int, str], Dict[str, Any]]], + Optional[dict[Union[int, str], dict[str, Any]]], Doc( """ Additional responses that could be returned by this *path operation*. @@ -3283,7 +3281,7 @@ class APIRouter(routing.Router): ), ] = True, response_class: Annotated[ - Type[Response], + type[Response], Doc( """ Response class to be used for this *path operation*. @@ -3304,7 +3302,7 @@ class APIRouter(routing.Router): ), ] = None, callbacks: Annotated[ - Optional[List[BaseRoute]], + Optional[list[BaseRoute]], Doc( """ List of *path operations* that will be used as OpenAPI callbacks. @@ -3320,7 +3318,7 @@ class APIRouter(routing.Router): ), ] = None, openapi_extra: Annotated[ - Optional[Dict[str, Any]], + Optional[dict[str, Any]], Doc( """ Extra metadata to be included in the OpenAPI schema for this *path @@ -3453,7 +3451,7 @@ class APIRouter(routing.Router): ), ] = None, tags: Annotated[ - Optional[List[Union[str, Enum]]], + Optional[list[Union[str, Enum]]], Doc( """ A list of tags to be applied to the *path operation*. @@ -3519,7 +3517,7 @@ class APIRouter(routing.Router): ), ] = "Successful Response", responses: Annotated[ - Optional[Dict[Union[int, str], Dict[str, Any]]], + Optional[dict[Union[int, str], dict[str, Any]]], Doc( """ Additional responses that could be returned by this *path operation*. @@ -3660,7 +3658,7 @@ class APIRouter(routing.Router): ), ] = True, response_class: Annotated[ - Type[Response], + type[Response], Doc( """ Response class to be used for this *path operation*. @@ -3681,7 +3679,7 @@ class APIRouter(routing.Router): ), ] = None, callbacks: Annotated[ - Optional[List[BaseRoute]], + Optional[list[BaseRoute]], Doc( """ List of *path operations* that will be used as OpenAPI callbacks. @@ -3697,7 +3695,7 @@ class APIRouter(routing.Router): ), ] = None, openapi_extra: Annotated[ - Optional[Dict[str, Any]], + Optional[dict[str, Any]], Doc( """ Extra metadata to be included in the OpenAPI schema for this *path @@ -3835,7 +3833,7 @@ class APIRouter(routing.Router): ), ] = None, tags: Annotated[ - Optional[List[Union[str, Enum]]], + Optional[list[Union[str, Enum]]], Doc( """ A list of tags to be applied to the *path operation*. @@ -3901,7 +3899,7 @@ class APIRouter(routing.Router): ), ] = "Successful Response", responses: Annotated[ - Optional[Dict[Union[int, str], Dict[str, Any]]], + Optional[dict[Union[int, str], dict[str, Any]]], Doc( """ Additional responses that could be returned by this *path operation*. @@ -4042,7 +4040,7 @@ class APIRouter(routing.Router): ), ] = True, response_class: Annotated[ - Type[Response], + type[Response], Doc( """ Response class to be used for this *path operation*. @@ -4063,7 +4061,7 @@ class APIRouter(routing.Router): ), ] = None, callbacks: Annotated[ - Optional[List[BaseRoute]], + Optional[list[BaseRoute]], Doc( """ List of *path operations* that will be used as OpenAPI callbacks. @@ -4079,7 +4077,7 @@ class APIRouter(routing.Router): ), ] = None, openapi_extra: Annotated[ - Optional[Dict[str, Any]], + Optional[dict[str, Any]], Doc( """ Extra metadata to be included in the OpenAPI schema for this *path @@ -4217,7 +4215,7 @@ class APIRouter(routing.Router): ), ] = None, tags: Annotated[ - Optional[List[Union[str, Enum]]], + Optional[list[Union[str, Enum]]], Doc( """ A list of tags to be applied to the *path operation*. @@ -4283,7 +4281,7 @@ class APIRouter(routing.Router): ), ] = "Successful Response", responses: Annotated[ - Optional[Dict[Union[int, str], Dict[str, Any]]], + Optional[dict[Union[int, str], dict[str, Any]]], Doc( """ Additional responses that could be returned by this *path operation*. @@ -4424,7 +4422,7 @@ class APIRouter(routing.Router): ), ] = True, response_class: Annotated[ - Type[Response], + type[Response], Doc( """ Response class to be used for this *path operation*. @@ -4445,7 +4443,7 @@ class APIRouter(routing.Router): ), ] = None, callbacks: Annotated[ - Optional[List[BaseRoute]], + Optional[list[BaseRoute]], Doc( """ List of *path operations* that will be used as OpenAPI callbacks. @@ -4461,7 +4459,7 @@ class APIRouter(routing.Router): ), ] = None, openapi_extra: Annotated[ - Optional[Dict[str, Any]], + Optional[dict[str, Any]], Doc( """ Extra metadata to be included in the OpenAPI schema for this *path diff --git a/fastapi/security/api_key.py b/fastapi/security/api_key.py index 81c7be10d6..18dfb8e618 100644 --- a/fastapi/security/api_key.py +++ b/fastapi/security/api_key.py @@ -1,4 +1,4 @@ -from typing import Optional, Union +from typing import Annotated, Optional, Union from annotated_doc import Doc from fastapi.openapi.models import APIKey, APIKeyIn @@ -6,7 +6,6 @@ from fastapi.security.base import SecurityBase from starlette.exceptions import HTTPException from starlette.requests import Request from starlette.status import HTTP_401_UNAUTHORIZED -from typing_extensions import Annotated class APIKeyBase(SecurityBase): diff --git a/fastapi/security/http.py b/fastapi/security/http.py index 0d1bbba3a0..b4c3bc6d85 100644 --- a/fastapi/security/http.py +++ b/fastapi/security/http.py @@ -1,6 +1,6 @@ import binascii from base64 import b64decode -from typing import Dict, Optional +from typing import Annotated, Optional from annotated_doc import Doc from fastapi.exceptions import HTTPException @@ -11,7 +11,6 @@ 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 -from typing_extensions import Annotated class HTTPBasicCredentials(BaseModel): @@ -82,7 +81,7 @@ class HTTPBase(SecurityBase): self.scheme_name = scheme_name or self.__class__.__name__ self.auto_error = auto_error - def make_authenticate_headers(self) -> Dict[str, str]: + def make_authenticate_headers(self) -> dict[str, str]: return {"WWW-Authenticate": f"{self.model.scheme.title()}"} def make_not_authenticated_error(self) -> HTTPException: @@ -197,7 +196,7 @@ class HTTPBasic(HTTPBase): self.realm = realm self.auto_error = auto_error - def make_authenticate_headers(self) -> Dict[str, str]: + def make_authenticate_headers(self) -> dict[str, str]: if self.realm: return {"WWW-Authenticate": f'Basic realm="{self.realm}"'} return {"WWW-Authenticate": "Basic"} diff --git a/fastapi/security/oauth2.py b/fastapi/security/oauth2.py index b41b0f8778..fc49ba1903 100644 --- a/fastapi/security/oauth2.py +++ b/fastapi/security/oauth2.py @@ -1,4 +1,4 @@ -from typing import Any, Dict, List, Optional, Union, cast +from typing import Annotated, Any, Optional, Union, cast from annotated_doc import Doc from fastapi.exceptions import HTTPException @@ -10,9 +10,6 @@ from fastapi.security.utils import get_authorization_scheme_param from starlette.requests import Request from starlette.status import HTTP_401_UNAUTHORIZED -# TODO: import from typing when deprecating Python 3.9 -from typing_extensions import Annotated - class OAuth2PasswordRequestForm: """ @@ -323,7 +320,7 @@ class OAuth2(SecurityBase): self, *, flows: Annotated[ - Union[OAuthFlowsModel, Dict[str, Dict[str, Any]]], + Union[OAuthFlowsModel, dict[str, dict[str, Any]]], Doc( """ The dictionary of OAuth2 flows. @@ -440,7 +437,7 @@ class OAuth2PasswordBearer(OAuth2): ), ] = None, scopes: Annotated[ - Optional[Dict[str, str]], + Optional[dict[str, str]], Doc( """ The OAuth2 scopes that would be required by the *path operations* that @@ -553,7 +550,7 @@ class OAuth2AuthorizationCodeBearer(OAuth2): ), ] = None, scopes: Annotated[ - Optional[Dict[str, str]], + Optional[dict[str, str]], Doc( """ The OAuth2 scopes that would be required by the *path operations* that @@ -639,7 +636,7 @@ class SecurityScopes: def __init__( self, scopes: Annotated[ - Optional[List[str]], + Optional[list[str]], Doc( """ This will be filled by FastAPI. @@ -648,7 +645,7 @@ class SecurityScopes: ] = None, ): self.scopes: Annotated[ - List[str], + list[str], Doc( """ The list of all the scopes required by dependencies. diff --git a/fastapi/security/open_id_connect_url.py b/fastapi/security/open_id_connect_url.py index e574a56a82..f4d953351e 100644 --- a/fastapi/security/open_id_connect_url.py +++ b/fastapi/security/open_id_connect_url.py @@ -1,4 +1,4 @@ -from typing import Optional +from typing import Annotated, Optional from annotated_doc import Doc from fastapi.openapi.models import OpenIdConnect as OpenIdConnectModel @@ -6,7 +6,6 @@ from fastapi.security.base import SecurityBase from starlette.exceptions import HTTPException from starlette.requests import Request from starlette.status import HTTP_401_UNAUTHORIZED -from typing_extensions import Annotated class OpenIdConnect(SecurityBase): diff --git a/fastapi/security/utils.py b/fastapi/security/utils.py index fa7a450b74..002e68b445 100644 --- a/fastapi/security/utils.py +++ b/fastapi/security/utils.py @@ -1,9 +1,9 @@ -from typing import Optional, Tuple +from typing import Optional def get_authorization_scheme_param( authorization_header_value: Optional[str], -) -> Tuple[str, str]: +) -> tuple[str, str]: if not authorization_header_value: return "", "" scheme, _, param = authorization_header_value.partition(" ") diff --git a/fastapi/temp_pydantic_v1_params.py b/fastapi/temp_pydantic_v1_params.py index e41d712308..b6c804dc44 100644 --- a/fastapi/temp_pydantic_v1_params.py +++ b/fastapi/temp_pydantic_v1_params.py @@ -1,9 +1,9 @@ import warnings -from typing import Any, Callable, Dict, List, Optional, Union +from typing import Annotated, Any, Callable, Optional, Union from fastapi.openapi.models import Example from fastapi.params import ParamTypes -from typing_extensions import Annotated, deprecated +from typing_extensions import deprecated from ._compat.may_v1 import FieldInfo, Undefined from ._compat.shared import PYDANTIC_VERSION_MINOR_TUPLE @@ -47,7 +47,7 @@ class Param(FieldInfo): # type: ignore[misc] allow_inf_nan: Union[bool, None] = _Unset, max_digits: Union[int, None] = _Unset, decimal_places: Union[int, None] = _Unset, - examples: Optional[List[Any]] = None, + examples: Optional[list[Any]] = None, example: Annotated[ Optional[Any], deprecated( @@ -55,10 +55,10 @@ class Param(FieldInfo): # type: ignore[misc] "although still supported. Use examples instead." ), ] = _Unset, - openapi_examples: Optional[Dict[str, Example]] = None, + openapi_examples: Optional[dict[str, Example]] = None, deprecated: Union[deprecated, str, bool, None] = None, include_in_schema: bool = True, - json_schema_extra: Union[Dict[str, Any], None] = None, + json_schema_extra: Union[dict[str, Any], None] = None, **extra: Any, ): if example is not _Unset: @@ -148,7 +148,7 @@ class Path(Param): # type: ignore[misc] allow_inf_nan: Union[bool, None] = _Unset, max_digits: Union[int, None] = _Unset, decimal_places: Union[int, None] = _Unset, - examples: Optional[List[Any]] = None, + examples: Optional[list[Any]] = None, example: Annotated[ Optional[Any], deprecated( @@ -156,10 +156,10 @@ class Path(Param): # type: ignore[misc] "although still supported. Use examples instead." ), ] = _Unset, - openapi_examples: Optional[Dict[str, Example]] = None, + openapi_examples: Optional[dict[str, Example]] = None, deprecated: Union[deprecated, str, bool, None] = None, include_in_schema: bool = True, - json_schema_extra: Union[Dict[str, Any], None] = None, + json_schema_extra: Union[dict[str, Any], None] = None, **extra: Any, ): assert default is ..., "Path parameters cannot have a default value" @@ -234,7 +234,7 @@ class Query(Param): # type: ignore[misc] allow_inf_nan: Union[bool, None] = _Unset, max_digits: Union[int, None] = _Unset, decimal_places: Union[int, None] = _Unset, - examples: Optional[List[Any]] = None, + examples: Optional[list[Any]] = None, example: Annotated[ Optional[Any], deprecated( @@ -242,10 +242,10 @@ class Query(Param): # type: ignore[misc] "although still supported. Use examples instead." ), ] = _Unset, - openapi_examples: Optional[Dict[str, Example]] = None, + openapi_examples: Optional[dict[str, Example]] = None, deprecated: Union[deprecated, str, bool, None] = None, include_in_schema: bool = True, - json_schema_extra: Union[Dict[str, Any], None] = None, + json_schema_extra: Union[dict[str, Any], None] = None, **extra: Any, ): super().__init__( @@ -319,7 +319,7 @@ class Header(Param): # type: ignore[misc] allow_inf_nan: Union[bool, None] = _Unset, max_digits: Union[int, None] = _Unset, decimal_places: Union[int, None] = _Unset, - examples: Optional[List[Any]] = None, + examples: Optional[list[Any]] = None, example: Annotated[ Optional[Any], deprecated( @@ -327,10 +327,10 @@ class Header(Param): # type: ignore[misc] "although still supported. Use examples instead." ), ] = _Unset, - openapi_examples: Optional[Dict[str, Example]] = None, + openapi_examples: Optional[dict[str, Example]] = None, deprecated: Union[deprecated, str, bool, None] = None, include_in_schema: bool = True, - json_schema_extra: Union[Dict[str, Any], None] = None, + json_schema_extra: Union[dict[str, Any], None] = None, **extra: Any, ): self.convert_underscores = convert_underscores @@ -404,7 +404,7 @@ class Cookie(Param): # type: ignore[misc] allow_inf_nan: Union[bool, None] = _Unset, max_digits: Union[int, None] = _Unset, decimal_places: Union[int, None] = _Unset, - examples: Optional[List[Any]] = None, + examples: Optional[list[Any]] = None, example: Annotated[ Optional[Any], deprecated( @@ -412,10 +412,10 @@ class Cookie(Param): # type: ignore[misc] "although still supported. Use examples instead." ), ] = _Unset, - openapi_examples: Optional[Dict[str, Example]] = None, + openapi_examples: Optional[dict[str, Example]] = None, deprecated: Union[deprecated, str, bool, None] = None, include_in_schema: bool = True, - json_schema_extra: Union[Dict[str, Any], None] = None, + json_schema_extra: Union[dict[str, Any], None] = None, **extra: Any, ): super().__init__( @@ -488,7 +488,7 @@ class Body(FieldInfo): # type: ignore[misc] allow_inf_nan: Union[bool, None] = _Unset, max_digits: Union[int, None] = _Unset, decimal_places: Union[int, None] = _Unset, - examples: Optional[List[Any]] = None, + examples: Optional[list[Any]] = None, example: Annotated[ Optional[Any], deprecated( @@ -496,10 +496,10 @@ class Body(FieldInfo): # type: ignore[misc] "although still supported. Use examples instead." ), ] = _Unset, - openapi_examples: Optional[Dict[str, Example]] = None, + openapi_examples: Optional[dict[str, Example]] = None, deprecated: Union[deprecated, str, bool, None] = None, include_in_schema: bool = True, - json_schema_extra: Union[Dict[str, Any], None] = None, + json_schema_extra: Union[dict[str, Any], None] = None, **extra: Any, ): self.embed = embed @@ -591,7 +591,7 @@ class Form(Body): # type: ignore[misc] allow_inf_nan: Union[bool, None] = _Unset, max_digits: Union[int, None] = _Unset, decimal_places: Union[int, None] = _Unset, - examples: Optional[List[Any]] = None, + examples: Optional[list[Any]] = None, example: Annotated[ Optional[Any], deprecated( @@ -599,10 +599,10 @@ class Form(Body): # type: ignore[misc] "although still supported. Use examples instead." ), ] = _Unset, - openapi_examples: Optional[Dict[str, Example]] = None, + openapi_examples: Optional[dict[str, Example]] = None, deprecated: Union[deprecated, str, bool, None] = None, include_in_schema: bool = True, - json_schema_extra: Union[Dict[str, Any], None] = None, + json_schema_extra: Union[dict[str, Any], None] = None, **extra: Any, ): super().__init__( @@ -675,7 +675,7 @@ class File(Form): # type: ignore[misc] allow_inf_nan: Union[bool, None] = _Unset, max_digits: Union[int, None] = _Unset, decimal_places: Union[int, None] = _Unset, - examples: Optional[List[Any]] = None, + examples: Optional[list[Any]] = None, example: Annotated[ Optional[Any], deprecated( @@ -683,10 +683,10 @@ class File(Form): # type: ignore[misc] "although still supported. Use examples instead." ), ] = _Unset, - openapi_examples: Optional[Dict[str, Example]] = None, + openapi_examples: Optional[dict[str, Example]] = None, deprecated: Union[deprecated, str, bool, None] = None, include_in_schema: bool = True, - json_schema_extra: Union[Dict[str, Any], None] = None, + json_schema_extra: Union[dict[str, Any], None] = None, **extra: Any, ): super().__init__( diff --git a/fastapi/types.py b/fastapi/types.py index 3f4e81a7cc..d3e980cb43 100644 --- a/fastapi/types.py +++ b/fastapi/types.py @@ -1,11 +1,11 @@ import types from enum import Enum -from typing import Any, Callable, Dict, Optional, Set, Tuple, Type, TypeVar, Union +from typing import Any, Callable, Optional, TypeVar, Union from pydantic import BaseModel 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] +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] diff --git a/fastapi/utils.py b/fastapi/utils.py index b3b89ed2b4..5b93b9af8e 100644 --- a/fastapi/utils.py +++ b/fastapi/utils.py @@ -1,14 +1,11 @@ import re import warnings +from collections.abc import MutableMapping from dataclasses import is_dataclass from typing import ( TYPE_CHECKING, Any, - Dict, - MutableMapping, Optional, - Set, - Type, Union, cast, ) @@ -36,7 +33,7 @@ if TYPE_CHECKING: # pragma: nocover from .routing import APIRoute # Cache for `create_cloned_field` -_CLONED_TYPES_CACHE: MutableMapping[Type[BaseModel], Type[BaseModel]] = ( +_CLONED_TYPES_CACHE: MutableMapping[type[BaseModel], type[BaseModel]] = ( WeakKeyDictionary() ) @@ -58,7 +55,7 @@ def is_body_allowed_for_status_code(status_code: Union[int, str, None]) -> bool: return not (current_status_code < 200 or current_status_code in {204, 205, 304}) -def get_path_param_names(path: str) -> Set[str]: +def get_path_param_names(path: str) -> set[str]: return set(re.findall("{(.*?)}", path)) @@ -76,10 +73,10 @@ _invalid_args_message = ( def create_model_field( name: str, type_: Any, - class_validators: Optional[Dict[str, Validator]] = None, + class_validators: Optional[dict[str, Validator]] = None, default: Optional[Any] = Undefined, required: Union[bool, UndefinedType] = Undefined, - model_config: Union[Type[BaseConfig], None] = None, + model_config: Union[type[BaseConfig], None] = None, field_info: Optional[FieldInfo] = None, alias: Optional[str] = None, mode: Literal["validation", "serialization"] = "validation", @@ -141,7 +138,7 @@ def create_model_field( def create_cloned_field( field: ModelField, *, - cloned_types: Optional[MutableMapping[Type[BaseModel], Type[BaseModel]]] = None, + cloned_types: Optional[MutableMapping[type[BaseModel], type[BaseModel]]] = None, ) -> ModelField: if PYDANTIC_V2: from ._compat import v2 @@ -161,7 +158,7 @@ def create_cloned_field( original_type = original_type.__pydantic_model__ use_type = original_type if lenient_issubclass(original_type, v1.BaseModel): - original_type = cast(Type[v1.BaseModel], original_type) + original_type = cast(type[v1.BaseModel], original_type) use_type = cloned_types.get(original_type) if use_type is None: use_type = v1.create_model(original_type.__name__, __base__=original_type) @@ -224,7 +221,7 @@ def generate_unique_id(route: "APIRoute") -> str: return operation_id -def deep_dict_update(main_dict: Dict[Any, Any], update_dict: Dict[Any, Any]) -> None: +def deep_dict_update(main_dict: dict[Any, Any], update_dict: dict[Any, Any]) -> None: for key, value in update_dict.items(): if ( key in main_dict diff --git a/pdm_build.py b/pdm_build.py index c83222b336..a0eb88eebb 100644 --- a/pdm_build.py +++ b/pdm_build.py @@ -1,5 +1,5 @@ import os -from typing import Any, Dict +from typing import Any from pdm.backend.hooks import Context @@ -9,12 +9,12 @@ TIANGOLO_BUILD_PACKAGE = os.getenv("TIANGOLO_BUILD_PACKAGE", "fastapi") def pdm_build_initialize(context: Context) -> None: metadata = context.config.metadata # Get custom config for the current package, from the env var - config: Dict[str, Any] = context.config.data["tool"]["tiangolo"][ + config: dict[str, Any] = context.config.data["tool"]["tiangolo"][ "_internal-slim-build" ]["packages"].get(TIANGOLO_BUILD_PACKAGE) if not config: return - project_config: Dict[str, Any] = config["project"] + project_config: dict[str, Any] = config["project"] # Override main [project] configs with custom configs for this package for key, value in project_config.items(): metadata[key] = value diff --git a/pyproject.toml b/pyproject.toml index ef4440b1b4..dd16e1f8fa 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -9,7 +9,7 @@ description = "FastAPI framework, high performance, easy to learn, fast to code, readme = "README.md" license = "MIT" license-files = ["LICENSE"] -requires-python = ">=3.8" +requires-python = ">=3.9" authors = [ { name = "Sebastián Ramírez", email = "tiangolo@gmail.com" }, ] @@ -34,7 +34,6 @@ classifiers = [ "Framework :: Pydantic :: 2", "Intended Audience :: Developers", "Programming Language :: Python :: 3 :: Only", - "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", @@ -200,7 +199,7 @@ relative_files = true context = '${CONTEXT}' dynamic_context = "test_function" omit = [ - "docs_src/response_model/tutorial003_04.py", + "docs_src/response_model/tutorial003_04_py39.py", "docs_src/response_model/tutorial003_04_py310.py", ] @@ -230,41 +229,30 @@ ignore = [ [tool.ruff.lint.per-file-ignores] "__init__.py" = ["F401"] -"docs_src/dependencies/tutorial007.py" = ["F821"] -"docs_src/dependencies/tutorial008.py" = ["F821"] -"docs_src/dependencies/tutorial009.py" = ["F821"] -"docs_src/dependencies/tutorial010.py" = ["F821"] -"docs_src/custom_response/tutorial007.py" = ["B007"] -"docs_src/dataclasses/tutorial003.py" = ["I001"] -"docs_src/path_operation_advanced_configuration/tutorial007.py" = ["B904"] +"docs_src/dependencies/tutorial007_py39.py" = ["F821"] +"docs_src/dependencies/tutorial008_py39.py" = ["F821"] +"docs_src/dependencies/tutorial009_py39.py" = ["F821"] +"docs_src/dependencies/tutorial010_py39.py" = ["F821"] +"docs_src/custom_response/tutorial007_py39.py" = ["B007"] +"docs_src/dataclasses/tutorial003_py39.py" = ["I001"] "docs_src/path_operation_advanced_configuration/tutorial007_py39.py" = ["B904"] -"docs_src/path_operation_advanced_configuration/tutorial007_pv1.py" = ["B904"] "docs_src/path_operation_advanced_configuration/tutorial007_pv1_py39.py" = ["B904"] -"docs_src/custom_request_and_route/tutorial002.py" = ["B904"] "docs_src/custom_request_and_route/tutorial002_py39.py" = ["B904"] "docs_src/custom_request_and_route/tutorial002_py310.py" = ["B904"] -"docs_src/custom_request_and_route/tutorial002_an.py" = ["B904"] "docs_src/custom_request_and_route/tutorial002_an_py39.py" = ["B904"] "docs_src/custom_request_and_route/tutorial002_an_py310.py" = ["B904"] -"docs_src/dependencies/tutorial008_an.py" = ["F821"] "docs_src/dependencies/tutorial008_an_py39.py" = ["F821"] -"docs_src/query_params_str_validations/tutorial012_an.py" = ["B006"] "docs_src/query_params_str_validations/tutorial012_an_py39.py" = ["B006"] -"docs_src/query_params_str_validations/tutorial013_an.py" = ["B006"] "docs_src/query_params_str_validations/tutorial013_an_py39.py" = ["B006"] -"docs_src/security/tutorial004.py" = ["B904"] -"docs_src/security/tutorial004_an.py" = ["B904"] -"docs_src/security/tutorial004_an_py310.py" = ["B904"] +"docs_src/security/tutorial004_py39.py" = ["B904"] "docs_src/security/tutorial004_an_py39.py" = ["B904"] +"docs_src/security/tutorial004_an_py310.py" = ["B904"] "docs_src/security/tutorial004_py310.py" = ["B904"] -"docs_src/security/tutorial005.py" = ["B904"] -"docs_src/security/tutorial005_an.py" = ["B904"] "docs_src/security/tutorial005_an_py310.py" = ["B904"] "docs_src/security/tutorial005_an_py39.py" = ["B904"] "docs_src/security/tutorial005_py310.py" = ["B904"] "docs_src/security/tutorial005_py39.py" = ["B904"] -"docs_src/dependencies/tutorial008b.py" = ["B904"] -"docs_src/dependencies/tutorial008b_an.py" = ["B904"] +"docs_src/dependencies/tutorial008b_py39.py" = ["B904"] "docs_src/dependencies/tutorial008b_an_py39.py" = ["B904"] diff --git a/requirements-tests.txt b/requirements-tests.txt index c5de4157e7..ee188b496c 100644 --- a/requirements-tests.txt +++ b/requirements-tests.txt @@ -11,6 +11,7 @@ PyJWT==2.9.0 pyyaml >=5.3.1,<7.0.0 pwdlib[argon2] >=0.2.1 inline-snapshot>=0.21.1 +pytest-codspeed==4.2.0 # types types-ujson ==5.10.0.20240515 types-orjson ==3.6.2 diff --git a/scripts/docs.py b/scripts/docs.py index b35bb3627f..bf7d9de395 100644 --- a/scripts/docs.py +++ b/scripts/docs.py @@ -8,7 +8,7 @@ from html.parser import HTMLParser from http.server import HTTPServer, SimpleHTTPRequestHandler from multiprocessing import Pool from pathlib import Path -from typing import Any, Dict, List, Optional, Union +from typing import Any, Optional, Union import mkdocs.utils import typer @@ -82,11 +82,11 @@ def slugify(text: str) -> str: ) -def get_en_config() -> Dict[str, Any]: +def get_en_config() -> dict[str, Any]: return mkdocs.utils.yaml_load(en_config_path.read_text(encoding="utf-8")) -def get_lang_paths() -> List[Path]: +def get_lang_paths() -> list[Path]: return sorted(docs_path.iterdir()) @@ -334,14 +334,14 @@ def live( ) -def get_updated_config_content() -> Dict[str, Any]: +def get_updated_config_content() -> dict[str, Any]: config = get_en_config() languages = [{"en": "/"}] - new_alternate: List[Dict[str, str]] = [] + new_alternate: list[dict[str, str]] = [] # Language names sourced from https://quickref.me/iso-639-1 # Contributors may wish to update or change these, e.g. to fix capitalization. language_names_path = Path(__file__).parent / "../docs/language_names.yml" - local_language_names: Dict[str, str] = mkdocs.utils.yaml_load( + local_language_names: dict[str, str] = mkdocs.utils.yaml_load( language_names_path.read_text(encoding="utf-8") ) for lang_path in get_lang_paths(): @@ -530,7 +530,7 @@ def add_permalinks_page(path: Path, update_existing: bool = False): @app.command() -def add_permalinks_pages(pages: List[Path], update_existing: bool = False) -> None: +def add_permalinks_pages(pages: list[Path], update_existing: bool = False) -> None: """ Add or update header permalinks in specific pages of En docs. """ diff --git a/scripts/mkdocs_hooks.py b/scripts/mkdocs_hooks.py index 09cfa99e38..4b781270a2 100644 --- a/scripts/mkdocs_hooks.py +++ b/scripts/mkdocs_hooks.py @@ -1,6 +1,6 @@ from functools import lru_cache from pathlib import Path -from typing import Any, List, Union +from typing import Any, Union import material from mkdocs.config.defaults import MkDocsConfig @@ -27,7 +27,7 @@ def get_missing_translation_content(docs_dir: str) -> str: @lru_cache -def get_mkdocs_material_langs() -> List[str]: +def get_mkdocs_material_langs() -> list[str]: material_path = Path(material.__file__).parent material_langs_path = material_path / "templates" / "partials" / "languages" langs = [file.stem for file in material_langs_path.glob("*.html")] @@ -65,7 +65,7 @@ def resolve_file(*, item: str, files: Files, config: MkDocsConfig) -> None: ) -def resolve_files(*, items: List[Any], files: Files, config: MkDocsConfig) -> None: +def resolve_files(*, items: list[Any], files: Files, config: MkDocsConfig) -> None: for item in items: if isinstance(item, str): resolve_file(item=item, files=files, config=config) @@ -94,9 +94,9 @@ def on_files(files: Files, *, config: MkDocsConfig) -> Files: def generate_renamed_section_items( - items: List[Union[Page, Section, Link]], *, config: MkDocsConfig -) -> List[Union[Page, Section, Link]]: - new_items: List[Union[Page, Section, Link]] = [] + items: list[Union[Page, Section, Link]], *, config: MkDocsConfig +) -> list[Union[Page, Section, Link]]: + new_items: list[Union[Page, Section, Link]] = [] for item in items: if isinstance(item, Section): new_title = item.title diff --git a/scripts/notify_translations.py b/scripts/notify_translations.py index c300624db2..2ca740a607 100644 --- a/scripts/notify_translations.py +++ b/scripts/notify_translations.py @@ -3,7 +3,7 @@ import random import sys import time from pathlib import Path -from typing import Any, Dict, List, Union, cast +from typing import Any, Union, cast import httpx from github import Github @@ -120,7 +120,7 @@ class CommentsEdge(BaseModel): class Comments(BaseModel): - edges: List[CommentsEdge] + edges: list[CommentsEdge] class CommentsDiscussion(BaseModel): @@ -149,7 +149,7 @@ class AllDiscussionsLabelsEdge(BaseModel): class AllDiscussionsDiscussionLabels(BaseModel): - edges: List[AllDiscussionsLabelsEdge] + edges: list[AllDiscussionsLabelsEdge] class AllDiscussionsDiscussionNode(BaseModel): @@ -160,7 +160,7 @@ class AllDiscussionsDiscussionNode(BaseModel): class AllDiscussionsDiscussions(BaseModel): - nodes: List[AllDiscussionsDiscussionNode] + nodes: list[AllDiscussionsDiscussionNode] class AllDiscussionsRepository(BaseModel): @@ -205,7 +205,7 @@ def get_graphql_response( discussion_id: Union[str, None] = None, comment_id: Union[str, None] = None, body: Union[str, None] = None, -) -> Dict[str, Any]: +) -> dict[str, Any]: headers = {"Authorization": f"token {settings.github_token.get_secret_value()}"} variables = { "after": after, @@ -233,12 +233,12 @@ def get_graphql_response( logging.error(data["errors"]) logging.error(response.text) raise RuntimeError(response.text) - return cast(Dict[str, Any], data) + return cast(dict[str, Any], data) def get_graphql_translation_discussions( *, settings: Settings -) -> List[AllDiscussionsDiscussionNode]: +) -> list[AllDiscussionsDiscussionNode]: data = get_graphql_response( settings=settings, query=all_discussions_query, @@ -250,7 +250,7 @@ def get_graphql_translation_discussions( def get_graphql_translation_discussion_comments_edges( *, settings: Settings, discussion_number: int, after: Union[str, None] = None -) -> List[CommentsEdge]: +) -> list[CommentsEdge]: data = get_graphql_response( settings=settings, query=translation_discussion_query, @@ -264,7 +264,7 @@ def get_graphql_translation_discussion_comments_edges( def get_graphql_translation_discussion_comments( *, settings: Settings, discussion_number: int ) -> list[Comment]: - comment_nodes: List[Comment] = [] + comment_nodes: list[Comment] = [] discussion_edges = get_graphql_translation_discussion_comments_edges( settings=settings, discussion_number=discussion_number ) @@ -348,7 +348,7 @@ def main() -> None: # Generate translation map, lang ID to discussion discussions = get_graphql_translation_discussions(settings=settings) - lang_to_discussion_map: Dict[str, AllDiscussionsDiscussionNode] = {} + lang_to_discussion_map: dict[str, AllDiscussionsDiscussionNode] = {} for discussion in discussions: for edge in discussion.labels.edges: label = edge.node.name diff --git a/scripts/people.py b/scripts/people.py index 65e009944c..207ab46493 100644 --- a/scripts/people.py +++ b/scripts/people.py @@ -3,9 +3,10 @@ import secrets import subprocess import time from collections import Counter +from collections.abc import Container from datetime import datetime, timedelta, timezone from pathlib import Path -from typing import Any, Container, Union +from typing import Any, Union import httpx import yaml diff --git a/docs_src/settings/app02/__init__.py b/tests/benchmarks/__init__.py similarity index 100% rename from docs_src/settings/app02/__init__.py rename to tests/benchmarks/__init__.py diff --git a/tests/benchmarks/test_general_performance.py b/tests/benchmarks/test_general_performance.py new file mode 100644 index 0000000000..dca3613d00 --- /dev/null +++ b/tests/benchmarks/test_general_performance.py @@ -0,0 +1,396 @@ +import json +import sys +from collections.abc import Iterator +from typing import Annotated, Any + +import pytest +from fastapi import Depends, FastAPI +from fastapi.testclient import TestClient + +if "--codspeed" not in sys.argv: + pytest.skip( + "Benchmark tests are skipped by default; run with --codspeed.", + allow_module_level=True, + ) + +LARGE_ITEMS: list[dict[str, Any]] = [ + { + "id": i, + "name": f"item-{i}", + "values": list(range(25)), + "meta": { + "active": True, + "group": i % 10, + "tag": f"t{i % 5}", + }, + } + for i in range(300) +] + +LARGE_METADATA: dict[str, Any] = { + "source": "benchmark", + "version": 1, + "flags": {"a": True, "b": False, "c": True}, + "notes": ["x" * 50, "y" * 50, "z" * 50], +} + +LARGE_PAYLOAD: dict[str, Any] = {"items": LARGE_ITEMS, "metadata": LARGE_METADATA} + + +def dep_a(): + return 40 + + +def dep_b(a: Annotated[int, Depends(dep_a)]): + return a + 2 + + +@pytest.fixture( + scope="module", + params=[ + "pydantic-v2", + "pydantic-v1", + ], +) +def basemodel_class(request: pytest.FixtureRequest) -> type[Any]: + if request.param == "pydantic-v2": + from pydantic import BaseModel + + return BaseModel + else: + from pydantic.v1 import BaseModel + + return BaseModel + + +@pytest.fixture(scope="module") +def app(basemodel_class: type[Any]) -> FastAPI: + class ItemIn(basemodel_class): + name: str + value: int + + class ItemOut(basemodel_class): + name: str + value: int + dep: int + + class LargeIn(basemodel_class): + items: list[dict[str, Any]] + metadata: dict[str, Any] + + class LargeOut(basemodel_class): + items: list[dict[str, Any]] + metadata: dict[str, Any] + + app = FastAPI() + + @app.post("/sync/validated", response_model=ItemOut) + def sync_validated(item: ItemIn, dep: Annotated[int, Depends(dep_b)]): + return ItemOut(name=item.name, value=item.value, dep=dep) + + @app.get("/sync/dict-no-response-model") + def sync_dict_no_response_model(): + return {"name": "foo", "value": 123} + + @app.get("/sync/dict-with-response-model", response_model=ItemOut) + def sync_dict_with_response_model( + dep: Annotated[int, Depends(dep_b)], + ): + return {"name": "foo", "value": 123, "dep": dep} + + @app.get("/sync/model-no-response-model") + def sync_model_no_response_model(dep: Annotated[int, Depends(dep_b)]): + return ItemOut(name="foo", value=123, dep=dep) + + @app.get("/sync/model-with-response-model", response_model=ItemOut) + def sync_model_with_response_model(dep: Annotated[int, Depends(dep_b)]): + return ItemOut(name="foo", value=123, dep=dep) + + @app.post("/async/validated", response_model=ItemOut) + async def async_validated( + item: ItemIn, + dep: Annotated[int, Depends(dep_b)], + ): + return ItemOut(name=item.name, value=item.value, dep=dep) + + @app.post("/sync/large-receive") + def sync_large_receive(payload: LargeIn): + return {"received": len(payload.items)} + + @app.post("/async/large-receive") + async def async_large_receive(payload: LargeIn): + return {"received": len(payload.items)} + + @app.get("/sync/large-dict-no-response-model") + def sync_large_dict_no_response_model(): + return LARGE_PAYLOAD + + @app.get("/sync/large-dict-with-response-model", response_model=LargeOut) + def sync_large_dict_with_response_model(): + return LARGE_PAYLOAD + + @app.get("/sync/large-model-no-response-model") + def sync_large_model_no_response_model(): + return LargeOut(items=LARGE_ITEMS, metadata=LARGE_METADATA) + + @app.get("/sync/large-model-with-response-model", response_model=LargeOut) + def sync_large_model_with_response_model(): + return LargeOut(items=LARGE_ITEMS, metadata=LARGE_METADATA) + + @app.get("/async/large-dict-no-response-model") + async def async_large_dict_no_response_model(): + return LARGE_PAYLOAD + + @app.get("/async/large-dict-with-response-model", response_model=LargeOut) + async def async_large_dict_with_response_model(): + return LARGE_PAYLOAD + + @app.get("/async/large-model-no-response-model") + async def async_large_model_no_response_model(): + return LargeOut(items=LARGE_ITEMS, metadata=LARGE_METADATA) + + @app.get("/async/large-model-with-response-model", response_model=LargeOut) + async def async_large_model_with_response_model(): + return LargeOut(items=LARGE_ITEMS, metadata=LARGE_METADATA) + + @app.get("/async/dict-no-response-model") + async def async_dict_no_response_model(): + return {"name": "foo", "value": 123} + + @app.get("/async/dict-with-response-model", response_model=ItemOut) + async def async_dict_with_response_model( + dep: Annotated[int, Depends(dep_b)], + ): + return {"name": "foo", "value": 123, "dep": dep} + + @app.get("/async/model-no-response-model") + async def async_model_no_response_model( + dep: Annotated[int, Depends(dep_b)], + ): + return ItemOut(name="foo", value=123, dep=dep) + + @app.get("/async/model-with-response-model", response_model=ItemOut) + async def async_model_with_response_model( + dep: Annotated[int, Depends(dep_b)], + ): + return ItemOut(name="foo", value=123, dep=dep) + + return app + + +@pytest.fixture(scope="module") +def client(app: FastAPI) -> Iterator[TestClient]: + with TestClient(app) as client: + yield client + + +def _bench_get(benchmark, client: TestClient, path: str) -> tuple[int, bytes]: + warmup = client.get(path) + assert warmup.status_code == 200 + + def do_request() -> tuple[int, bytes]: + response = client.get(path) + return response.status_code, response.content + + return benchmark(do_request) + + +def _bench_post_json( + benchmark, client: TestClient, path: str, json: dict[str, Any] +) -> tuple[int, bytes]: + warmup = client.post(path, json=json) + assert warmup.status_code == 200 + + def do_request() -> tuple[int, bytes]: + response = client.post(path, json=json) + return response.status_code, response.content + + return benchmark(do_request) + + +def test_sync_receiving_validated_pydantic_model(benchmark, client: TestClient) -> None: + status_code, body = _bench_post_json( + benchmark, + client, + "/sync/validated", + json={"name": "foo", "value": 123}, + ) + assert status_code == 200 + assert body == b'{"name":"foo","value":123,"dep":42}' + + +def test_sync_return_dict_without_response_model(benchmark, client: TestClient) -> None: + status_code, body = _bench_get(benchmark, client, "/sync/dict-no-response-model") + assert status_code == 200 + assert body == b'{"name":"foo","value":123}' + + +def test_sync_return_dict_with_response_model(benchmark, client: TestClient) -> None: + status_code, body = _bench_get(benchmark, client, "/sync/dict-with-response-model") + assert status_code == 200 + assert body == b'{"name":"foo","value":123,"dep":42}' + + +def test_sync_return_model_without_response_model( + benchmark, client: TestClient +) -> None: + status_code, body = _bench_get(benchmark, client, "/sync/model-no-response-model") + assert status_code == 200 + assert body == b'{"name":"foo","value":123,"dep":42}' + + +def test_sync_return_model_with_response_model(benchmark, client: TestClient) -> None: + status_code, body = _bench_get(benchmark, client, "/sync/model-with-response-model") + assert status_code == 200 + assert body == b'{"name":"foo","value":123,"dep":42}' + + +def test_async_receiving_validated_pydantic_model( + benchmark, client: TestClient +) -> None: + status_code, body = _bench_post_json( + benchmark, client, "/async/validated", json={"name": "foo", "value": 123} + ) + assert status_code == 200 + assert body == b'{"name":"foo","value":123,"dep":42}' + + +def test_async_return_dict_without_response_model( + benchmark, client: TestClient +) -> None: + status_code, body = _bench_get(benchmark, client, "/async/dict-no-response-model") + assert status_code == 200 + assert body == b'{"name":"foo","value":123}' + + +def test_async_return_dict_with_response_model(benchmark, client: TestClient) -> None: + status_code, body = _bench_get(benchmark, client, "/async/dict-with-response-model") + assert status_code == 200 + assert body == b'{"name":"foo","value":123,"dep":42}' + + +def test_async_return_model_without_response_model( + benchmark, client: TestClient +) -> None: + status_code, body = _bench_get(benchmark, client, "/async/model-no-response-model") + assert status_code == 200 + assert body == b'{"name":"foo","value":123,"dep":42}' + + +def test_async_return_model_with_response_model(benchmark, client: TestClient) -> None: + status_code, body = _bench_get( + benchmark, client, "/async/model-with-response-model" + ) + assert status_code == 200 + assert body == b'{"name":"foo","value":123,"dep":42}' + + +def test_sync_receiving_large_payload(benchmark, client: TestClient) -> None: + status_code, body = _bench_post_json( + benchmark, + client, + "/sync/large-receive", + json=LARGE_PAYLOAD, + ) + assert status_code == 200 + assert body == b'{"received":300}' + + +def test_async_receiving_large_payload(benchmark, client: TestClient) -> None: + status_code, body = _bench_post_json( + benchmark, + client, + "/async/large-receive", + json=LARGE_PAYLOAD, + ) + assert status_code == 200 + assert body == b'{"received":300}' + + +def _expected_large_payload_json_bytes() -> bytes: + return json.dumps( + LARGE_PAYLOAD, + ensure_ascii=False, + allow_nan=False, + separators=(",", ":"), + ).encode("utf-8") + + +def test_sync_return_large_dict_without_response_model( + benchmark, client: TestClient +) -> None: + status_code, body = _bench_get( + benchmark, client, "/sync/large-dict-no-response-model" + ) + assert status_code == 200 + assert body == _expected_large_payload_json_bytes() + + +def test_sync_return_large_dict_with_response_model( + benchmark, client: TestClient +) -> None: + status_code, body = _bench_get( + benchmark, client, "/sync/large-dict-with-response-model" + ) + assert status_code == 200 + assert body == _expected_large_payload_json_bytes() + + +def test_sync_return_large_model_without_response_model( + benchmark, client: TestClient +) -> None: + status_code, body = _bench_get( + benchmark, client, "/sync/large-model-no-response-model" + ) + assert status_code == 200 + assert body == _expected_large_payload_json_bytes() + + +def test_sync_return_large_model_with_response_model( + benchmark, client: TestClient +) -> None: + status_code, body = _bench_get( + benchmark, client, "/sync/large-model-with-response-model" + ) + assert status_code == 200 + assert body == _expected_large_payload_json_bytes() + + +def test_async_return_large_dict_without_response_model( + benchmark, client: TestClient +) -> None: + status_code, body = _bench_get( + benchmark, client, "/async/large-dict-no-response-model" + ) + assert status_code == 200 + assert body == _expected_large_payload_json_bytes() + + +def test_async_return_large_dict_with_response_model( + benchmark, client: TestClient +) -> None: + status_code, body = _bench_get( + benchmark, client, "/async/large-dict-with-response-model" + ) + assert status_code == 200 + assert body == _expected_large_payload_json_bytes() + + +def test_async_return_large_model_without_response_model( + benchmark, client: TestClient +) -> None: + status_code, body = _bench_get( + benchmark, client, "/async/large-model-no-response-model" + ) + assert status_code == 200 + assert body == _expected_large_payload_json_bytes() + + +def test_async_return_large_model_with_response_model( + benchmark, client: TestClient +) -> None: + status_code, body = _bench_get( + benchmark, client, "/async/large-model-with-response-model" + ) + assert status_code == 200 + assert body == _expected_large_payload_json_bytes() diff --git a/tests/main.py b/tests/main.py index 2f1d617115..7edb16c615 100644 --- a/tests/main.py +++ b/tests/main.py @@ -1,5 +1,5 @@ import http -from typing import FrozenSet, List, Optional +from typing import Optional from fastapi import FastAPI, Path, Query @@ -195,15 +195,15 @@ def get_enum_status_code(): @app.get("/query/frozenset") -def get_query_type_frozenset(query: FrozenSet[int] = Query(...)): +def get_query_type_frozenset(query: frozenset[int] = Query(...)): return ",".join(map(str, sorted(query))) @app.get("/query/list") -def get_query_list(device_ids: List[int] = Query()) -> List[int]: +def get_query_list(device_ids: list[int] = Query()) -> list[int]: return device_ids @app.get("/query/list-default") -def get_query_list_default(device_ids: List[int] = Query(default=[])) -> List[int]: +def get_query_list_default(device_ids: list[int] = Query(default=[])) -> list[int]: return device_ids diff --git a/tests/test_additional_properties.py b/tests/test_additional_properties.py index be14d10edc..2622366400 100644 --- a/tests/test_additional_properties.py +++ b/tests/test_additional_properties.py @@ -1,5 +1,3 @@ -from typing import Dict - from fastapi import FastAPI from fastapi.testclient import TestClient from pydantic import BaseModel @@ -8,7 +6,7 @@ app = FastAPI() class Items(BaseModel): - items: Dict[str, int] + items: dict[str, int] @app.post("/foo") diff --git a/tests/test_additional_responses_custom_validationerror.py b/tests/test_additional_responses_custom_validationerror.py index 9fec5c96d4..8724e5ecb8 100644 --- a/tests/test_additional_responses_custom_validationerror.py +++ b/tests/test_additional_responses_custom_validationerror.py @@ -1,5 +1,3 @@ -import typing - from fastapi import FastAPI from fastapi.responses import JSONResponse from fastapi.testclient import TestClient @@ -18,7 +16,7 @@ class Error(BaseModel): class JsonApiError(BaseModel): - errors: typing.List[Error] + errors: list[Error] @app.get( diff --git a/tests/test_additional_responses_response_class.py b/tests/test_additional_responses_response_class.py index 68753561c9..fecc3ee16b 100644 --- a/tests/test_additional_responses_response_class.py +++ b/tests/test_additional_responses_response_class.py @@ -1,5 +1,3 @@ -import typing - from fastapi import FastAPI from fastapi.responses import JSONResponse from fastapi.testclient import TestClient @@ -18,7 +16,7 @@ class Error(BaseModel): class JsonApiError(BaseModel): - errors: typing.List[Error] + errors: list[Error] @app.get( diff --git a/tests/test_allow_inf_nan_in_enforcing.py b/tests/test_allow_inf_nan_in_enforcing.py index 9e855fdf81..083a024af0 100644 --- a/tests/test_allow_inf_nan_in_enforcing.py +++ b/tests/test_allow_inf_nan_in_enforcing.py @@ -1,7 +1,8 @@ +from typing import Annotated + import pytest from fastapi import Body, FastAPI, Query from fastapi.testclient import TestClient -from typing_extensions import Annotated app = FastAPI() diff --git a/tests/test_ambiguous_params.py b/tests/test_ambiguous_params.py index 8a31442eb0..5e48782f8d 100644 --- a/tests/test_ambiguous_params.py +++ b/tests/test_ambiguous_params.py @@ -1,9 +1,10 @@ +from typing import Annotated + import pytest from fastapi import Depends, FastAPI, Path from fastapi.param_functions import Query from fastapi.testclient import TestClient from fastapi.utils import PYDANTIC_V2 -from typing_extensions import Annotated app = FastAPI() diff --git a/tests/test_annotated.py b/tests/test_annotated.py index 473d33e52c..a9e7c78c99 100644 --- a/tests/test_annotated.py +++ b/tests/test_annotated.py @@ -1,8 +1,9 @@ +from typing import Annotated + import pytest from dirty_equals import IsDict from fastapi import APIRouter, FastAPI, Query from fastapi.testclient import TestClient -from typing_extensions import Annotated app = FastAPI() diff --git a/tests/test_arbitrary_types.py b/tests/test_arbitrary_types.py index e5fa95ef22..8b8417bae0 100644 --- a/tests/test_arbitrary_types.py +++ b/tests/test_arbitrary_types.py @@ -1,10 +1,9 @@ -from typing import List +from typing import Annotated import pytest from fastapi import FastAPI from fastapi.testclient import TestClient from inline_snapshot import snapshot -from typing_extensions import Annotated from .utils import needs_pydanticv2 @@ -25,7 +24,7 @@ def get_client(): FakeNumpyArrayPydantic = Annotated[ FakeNumpyArray, - WithJsonSchema(TypeAdapter(List[float]).json_schema()), + WithJsonSchema(TypeAdapter(list[float]).json_schema()), PlainSerializer(lambda v: v.data), ] @@ -66,7 +65,7 @@ def test_typeadapter(): FakeNumpyArrayPydantic = Annotated[ FakeNumpyArray, - WithJsonSchema(TypeAdapter(List[float]).json_schema()), + WithJsonSchema(TypeAdapter(list[float]).json_schema()), PlainSerializer(lambda v: v.data), ] diff --git a/tests/test_compat.py b/tests/test_compat.py index 26537c5ab7..3f9d84d894 100644 --- a/tests/test_compat.py +++ b/tests/test_compat.py @@ -1,4 +1,4 @@ -from typing import Any, Dict, List, Union +from typing import Any, Union from fastapi import FastAPI, UploadFile from fastapi._compat import ( @@ -61,7 +61,7 @@ def test_complex(): app = FastAPI() @app.post("/") - def foo(foo: Union[str, List[int]]): + def foo(foo: Union[str, list[int]]): return foo client = TestClient(app) @@ -95,7 +95,7 @@ def test_propagates_pydantic2_model_config(): embedded_model: EmbeddedModel = EmbeddedModel() @app.post("/") - def foo(req: Model) -> Dict[str, Union[str, None]]: + def foo(req: Model) -> dict[str, Union[str, None]]: return { "value": req.value or None, "embedded_value": req.embedded_model.value or None, @@ -125,7 +125,7 @@ def test_is_bytes_sequence_annotation_union(): # TODO: in theory this would allow declaring types that could be lists of bytes # to be read from files and other types, but I'm not even sure it's a good idea # to support it as a first class "feature" - assert is_bytes_sequence_annotation(Union[List[str], List[bytes]]) + assert is_bytes_sequence_annotation(Union[list[str], list[bytes]]) def test_is_uploadfile_sequence_annotation(): @@ -133,7 +133,7 @@ def test_is_uploadfile_sequence_annotation(): # TODO: in theory this would allow declaring types that could be lists of UploadFile # and other types, but I'm not even sure it's a good idea to support it as a first # class "feature" - assert is_uploadfile_sequence_annotation(Union[List[str], List[UploadFile]]) + assert is_uploadfile_sequence_annotation(Union[list[str], list[UploadFile]]) @needs_pydanticv2 @@ -141,7 +141,7 @@ def test_serialize_sequence_value_with_optional_list(): """Test that serialize_sequence_value handles optional lists correctly.""" from fastapi._compat import v2 - field_info = FieldInfo(annotation=Union[List[str], None]) + field_info = FieldInfo(annotation=Union[list[str], None]) field = v2.ModelField(name="items", field_info=field_info) result = v2.serialize_sequence_value(field=field, value=["a", "b", "c"]) assert result == ["a", "b", "c"] @@ -166,7 +166,7 @@ def test_serialize_sequence_value_with_none_first_in_union(): """Test that serialize_sequence_value handles Union[None, List[...]] correctly.""" from fastapi._compat import v2 - field_info = FieldInfo(annotation=Union[None, List[str]]) + field_info = FieldInfo(annotation=Union[None, list[str]]) field = v2.ModelField(name="items", field_info=field_info) result = v2.serialize_sequence_value(field=field, value=["x", "y"]) assert result == ["x", "y"] @@ -179,7 +179,7 @@ def test_is_pv1_scalar_field(): # For coverage class Model(v1.BaseModel): - foo: Union[str, Dict[str, Any]] + foo: Union[str, dict[str, Any]] fields = v1.get_model_fields(Model) assert not is_scalar_field(fields[0]) diff --git a/tests/test_compat_params_v1.py b/tests/test_compat_params_v1.py index 7064761cb5..8829a0a611 100644 --- a/tests/test_compat_params_v1.py +++ b/tests/test_compat_params_v1.py @@ -1,5 +1,5 @@ import sys -from typing import List, Optional +from typing import Optional import pytest @@ -8,6 +8,8 @@ from tests.utils import pydantic_snapshot, skip_module_if_py_gte_314 if sys.version_info >= (3, 14): skip_module_if_py_gte_314() +from typing import Annotated + from fastapi import FastAPI from fastapi._compat.v1 import BaseModel from fastapi.temp_pydantic_v1_params import ( @@ -21,7 +23,6 @@ from fastapi.temp_pydantic_v1_params import ( ) from fastapi.testclient import TestClient from inline_snapshot import snapshot -from typing_extensions import Annotated class Item(BaseModel): @@ -112,7 +113,7 @@ def upload_file( @app.post("/upload-multiple/") def upload_multiple_files( - files: Annotated[List[bytes], File()], + files: Annotated[list[bytes], File()], note: Annotated[str, Form()] = "", ): return { diff --git a/tests/test_custom_schema_fields.py b/tests/test_custom_schema_fields.py index d890291b19..bc3e1c5ec3 100644 --- a/tests/test_custom_schema_fields.py +++ b/tests/test_custom_schema_fields.py @@ -1,10 +1,9 @@ -from typing import Optional +from typing import Annotated, Optional from fastapi import FastAPI from fastapi._compat import PYDANTIC_V2 from fastapi.testclient import TestClient from pydantic import BaseModel -from typing_extensions import Annotated if PYDANTIC_V2: from pydantic import WithJsonSchema diff --git a/tests/test_datastructures.py b/tests/test_datastructures.py index 7e57d525ce..c175147bc3 100644 --- a/tests/test_datastructures.py +++ b/tests/test_datastructures.py @@ -1,6 +1,5 @@ import io from pathlib import Path -from typing import List import pytest from fastapi import FastAPI, UploadFile @@ -38,7 +37,7 @@ def test_upload_file_is_closed(tmp_path: Path): path.write_bytes(b"") app = FastAPI() - testing_file_store: List[UploadFile] = [] + testing_file_store: list[UploadFile] = [] @app.post("/uploadfile/") def create_upload_file(file: UploadFile): diff --git a/tests/test_dependency_after_yield_raise.py b/tests/test_dependency_after_yield_raise.py index b560dc36f9..b561402772 100644 --- a/tests/test_dependency_after_yield_raise.py +++ b/tests/test_dependency_after_yield_raise.py @@ -1,9 +1,8 @@ -from typing import Any +from typing import Annotated, Any import pytest from fastapi import Depends, FastAPI, HTTPException from fastapi.testclient import TestClient -from typing_extensions import Annotated class CustomError(Exception): diff --git a/tests/test_dependency_after_yield_streaming.py b/tests/test_dependency_after_yield_streaming.py index 7e1c8822b8..cbadff8f87 100644 --- a/tests/test_dependency_after_yield_streaming.py +++ b/tests/test_dependency_after_yield_streaming.py @@ -1,11 +1,11 @@ +from collections.abc import Generator from contextlib import contextmanager -from typing import Any, Generator +from typing import Annotated, Any import pytest from fastapi import Depends, FastAPI from fastapi.responses import StreamingResponse from fastapi.testclient import TestClient -from typing_extensions import Annotated class Session: diff --git a/tests/test_dependency_after_yield_websockets.py b/tests/test_dependency_after_yield_websockets.py index 7c323c338b..0fdf697b6c 100644 --- a/tests/test_dependency_after_yield_websockets.py +++ b/tests/test_dependency_after_yield_websockets.py @@ -1,10 +1,10 @@ +from collections.abc import Generator from contextlib import contextmanager -from typing import Any, Generator +from typing import Annotated, Any import pytest from fastapi import Depends, FastAPI, WebSocket from fastapi.testclient import TestClient -from typing_extensions import Annotated class Session: diff --git a/tests/test_dependency_class.py b/tests/test_dependency_class.py index 75241b467a..95ff3e9d95 100644 --- a/tests/test_dependency_class.py +++ b/tests/test_dependency_class.py @@ -1,4 +1,4 @@ -from typing import AsyncGenerator, Generator +from collections.abc import AsyncGenerator, Generator import pytest from fastapi import Depends, FastAPI diff --git a/tests/test_dependency_contextmanager.py b/tests/test_dependency_contextmanager.py index 02c10458cb..5a89934741 100644 --- a/tests/test_dependency_contextmanager.py +++ b/tests/test_dependency_contextmanager.py @@ -1,5 +1,4 @@ import json -from typing import Dict import pytest from fastapi import BackgroundTasks, Depends, FastAPI @@ -37,19 +36,19 @@ class OtherDependencyError(Exception): pass -async def asyncgen_state(state: Dict[str, str] = Depends(get_state)): +async def asyncgen_state(state: dict[str, str] = Depends(get_state)): state["/async"] = "asyncgen started" yield state["/async"] state["/async"] = "asyncgen completed" -def generator_state(state: Dict[str, str] = Depends(get_state)): +def generator_state(state: dict[str, str] = Depends(get_state)): state["/sync"] = "generator started" yield state["/sync"] state["/sync"] = "generator completed" -async def asyncgen_state_try(state: Dict[str, str] = Depends(get_state)): +async def asyncgen_state_try(state: dict[str, str] = Depends(get_state)): state["/async_raise"] = "asyncgen raise started" try: yield state["/async_raise"] @@ -60,7 +59,7 @@ async def asyncgen_state_try(state: Dict[str, str] = Depends(get_state)): state["/async_raise"] = "asyncgen raise finalized" -def generator_state_try(state: Dict[str, str] = Depends(get_state)): +def generator_state_try(state: dict[str, str] = Depends(get_state)): state["/sync_raise"] = "generator raise started" try: yield state["/sync_raise"] diff --git a/tests/test_dependency_contextvars.py b/tests/test_dependency_contextvars.py index 076802df84..0c2e5594b6 100644 --- a/tests/test_dependency_contextvars.py +++ b/tests/test_dependency_contextvars.py @@ -1,10 +1,11 @@ +from collections.abc import Awaitable from contextvars import ContextVar -from typing import Any, Awaitable, Callable, Dict, Optional +from typing import Any, Callable, Optional from fastapi import Depends, FastAPI, Request, Response from fastapi.testclient import TestClient -legacy_request_state_context_var: ContextVar[Optional[Dict[str, Any]]] = ContextVar( +legacy_request_state_context_var: ContextVar[Optional[dict[str, Any]]] = ContextVar( "legacy_request_state_context_var", default=None ) diff --git a/tests/test_dependency_duplicates.py b/tests/test_dependency_duplicates.py index 8e8d07c2d6..7c6717e2aa 100644 --- a/tests/test_dependency_duplicates.py +++ b/tests/test_dependency_duplicates.py @@ -1,5 +1,3 @@ -from typing import List - from dirty_equals import IsDict from fastapi import Depends, FastAPI from fastapi.testclient import TestClient @@ -40,7 +38,7 @@ async def no_duplicates(item: Item, item2: Item = Depends(dependency)): @app.post("/with-duplicates-sub") async def no_duplicates_sub( - item: Item, sub_items: List[Item] = Depends(sub_duplicate_dependency) + item: Item, sub_items: list[Item] = Depends(sub_duplicate_dependency) ): return [item, sub_items] diff --git a/tests/test_dependency_paramless.py b/tests/test_dependency_paramless.py index 9c3cc3878b..1774196fe4 100644 --- a/tests/test_dependency_paramless.py +++ b/tests/test_dependency_paramless.py @@ -1,4 +1,4 @@ -from typing import Union +from typing import Annotated, Union from fastapi import FastAPI, HTTPException, Security from fastapi.security import ( @@ -6,7 +6,6 @@ from fastapi.security import ( SecurityScopes, ) from fastapi.testclient import TestClient -from typing_extensions import Annotated app = FastAPI() diff --git a/tests/test_dependency_partial.py b/tests/test_dependency_partial.py index 61a76236f8..05a3cffa5a 100644 --- a/tests/test_dependency_partial.py +++ b/tests/test_dependency_partial.py @@ -1,10 +1,10 @@ +from collections.abc import AsyncGenerator, Generator from functools import partial -from typing import AsyncGenerator, Generator +from typing import Annotated import pytest from fastapi import Depends, FastAPI from fastapi.testclient import TestClient -from typing_extensions import Annotated app = FastAPI() diff --git a/tests/test_dependency_security_overrides.py b/tests/test_dependency_security_overrides.py index b89d82db43..14b65c7770 100644 --- a/tests/test_dependency_security_overrides.py +++ b/tests/test_dependency_security_overrides.py @@ -1,5 +1,3 @@ -from typing import List, Tuple - from fastapi import Depends, FastAPI, Security from fastapi.security import SecurityScopes from fastapi.testclient import TestClient @@ -25,8 +23,8 @@ def get_data_override(): @app.get("/user") def read_user( - user_data: Tuple[str, List[str]] = Security(get_user, scopes=["foo", "bar"]), - data: List[int] = Depends(get_data), + user_data: tuple[str, list[str]] = Security(get_user, scopes=["foo", "bar"]), + data: list[int] = Depends(get_data), ): return {"user": user_data[0], "scopes": user_data[1], "data": data} diff --git a/tests/test_dependency_wrapped.py b/tests/test_dependency_wrapped.py index 08356712d6..a4044112a2 100644 --- a/tests/test_dependency_wrapped.py +++ b/tests/test_dependency_wrapped.py @@ -1,7 +1,7 @@ import inspect import sys +from collections.abc import AsyncGenerator, Generator from functools import wraps -from typing import AsyncGenerator, Generator import pytest from fastapi import Depends, FastAPI diff --git a/tests/test_dependency_yield_scope.py b/tests/test_dependency_yield_scope.py index d87164fe80..f3fc3cc94f 100644 --- a/tests/test_dependency_yield_scope.py +++ b/tests/test_dependency_yield_scope.py @@ -1,12 +1,11 @@ import json -from typing import Any, Tuple +from typing import Annotated, Any import pytest from fastapi import APIRouter, Depends, FastAPI, HTTPException from fastapi.exceptions import FastAPIError from fastapi.responses import StreamingResponse from fastapi.testclient import TestClient -from typing_extensions import Annotated class Session: @@ -43,7 +42,7 @@ def get_named_session(session: SessionRequestDep, session_b: SessionDefaultDep) named_session.open = False -NamedSessionsDep = Annotated[Tuple[NamedSession, Session], Depends(get_named_session)] +NamedSessionsDep = Annotated[tuple[NamedSession, Session], Depends(get_named_session)] def get_named_func_session(session: SessionFuncDep) -> Any: @@ -58,14 +57,14 @@ def get_named_regular_func_session(session: SessionFuncDep) -> Any: BrokenSessionsDep = Annotated[ - Tuple[NamedSession, Session], Depends(get_named_func_session) + tuple[NamedSession, Session], Depends(get_named_func_session) ] NamedSessionsFuncDep = Annotated[ - Tuple[NamedSession, Session], Depends(get_named_func_session, scope="function") + tuple[NamedSession, Session], Depends(get_named_func_session, scope="function") ] RegularSessionsDep = Annotated[ - Tuple[NamedSession, Session], Depends(get_named_regular_func_session) + tuple[NamedSession, Session], Depends(get_named_regular_func_session) ] app = FastAPI() diff --git a/tests/test_dependency_yield_scope_websockets.py b/tests/test_dependency_yield_scope_websockets.py index 52a30ae7a7..dbe35e576c 100644 --- a/tests/test_dependency_yield_scope_websockets.py +++ b/tests/test_dependency_yield_scope_websockets.py @@ -1,13 +1,12 @@ from contextvars import ContextVar -from typing import Any, Dict, Tuple +from typing import Annotated, Any 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 +global_context: ContextVar[dict[str, Any]] = ContextVar("global_context", default={}) # noqa: B039 class Session: @@ -43,7 +42,7 @@ def get_named_session(session: SessionRequestDep, session_b: SessionDefaultDep) global_state["named_session_closed"] = True -NamedSessionsDep = Annotated[Tuple[NamedSession, Session], Depends(get_named_session)] +NamedSessionsDep = Annotated[tuple[NamedSession, Session], Depends(get_named_session)] def get_named_func_session(session: SessionFuncDep) -> Any: @@ -60,14 +59,14 @@ def get_named_regular_func_session(session: SessionFuncDep) -> Any: BrokenSessionsDep = Annotated[ - Tuple[NamedSession, Session], Depends(get_named_func_session) + tuple[NamedSession, Session], Depends(get_named_func_session) ] NamedSessionsFuncDep = Annotated[ - Tuple[NamedSession, Session], Depends(get_named_func_session, scope="function") + tuple[NamedSession, Session], Depends(get_named_func_session, scope="function") ] RegularSessionsDep = Annotated[ - Tuple[NamedSession, Session], Depends(get_named_regular_func_session) + tuple[NamedSession, Session], Depends(get_named_regular_func_session) ] app = FastAPI() diff --git a/tests/test_file_and_form_order_issue_9116.py b/tests/test_file_and_form_order_issue_9116.py index cb9a31d314..75290b60cd 100644 --- a/tests/test_file_and_form_order_issue_9116.py +++ b/tests/test_file_and_form_order_issue_9116.py @@ -4,12 +4,11 @@ See https://github.com/tiangolo/fastapi/discussions/9116 """ from pathlib import Path -from typing import List +from typing import Annotated import pytest from fastapi import FastAPI, File, Form from fastapi.testclient import TestClient -from typing_extensions import Annotated app = FastAPI() @@ -32,7 +31,7 @@ def file_after_form( @app.post("/file_list_before_form") def file_list_before_form( - files: Annotated[List[bytes], File()], + files: Annotated[list[bytes], File()], city: Annotated[str, Form()], ): return {"file_contents": files, "city": city} @@ -41,7 +40,7 @@ def file_list_before_form( @app.post("/file_list_after_form") def file_list_after_form( city: Annotated[str, Form()], - files: Annotated[List[bytes], File()], + files: Annotated[list[bytes], File()], ): return {"file_contents": files, "city": city} diff --git a/tests/test_form_default.py b/tests/test_form_default.py index 2a12049d1a..0b3eb8f2e2 100644 --- a/tests/test_form_default.py +++ b/tests/test_form_default.py @@ -1,8 +1,7 @@ -from typing import Optional +from typing import Annotated, Optional from fastapi import FastAPI, File, Form from starlette.testclient import TestClient -from typing_extensions import Annotated app = FastAPI() diff --git a/tests/test_forms_single_model.py b/tests/test_forms_single_model.py index 1db63f0214..b149b76539 100644 --- a/tests/test_forms_single_model.py +++ b/tests/test_forms_single_model.py @@ -1,11 +1,10 @@ -from typing import List, Optional +from typing import Annotated, Optional from dirty_equals import IsDict from fastapi import FastAPI, Form from fastapi._compat import PYDANTIC_V2 from fastapi.testclient import TestClient from pydantic import BaseModel, Field -from typing_extensions import Annotated app = FastAPI() @@ -14,7 +13,7 @@ class FormModel(BaseModel): username: str lastname: str age: Optional[int] = None - tags: List[str] = ["foo", "bar"] + tags: list[str] = ["foo", "bar"] alias_with: str = Field(alias="with", default="nothing") diff --git a/tests/test_forms_single_param.py b/tests/test_forms_single_param.py index 3bb951441f..67f054b34e 100644 --- a/tests/test_forms_single_param.py +++ b/tests/test_forms_single_param.py @@ -1,6 +1,7 @@ +from typing import Annotated + from fastapi import FastAPI, Form from fastapi.testclient import TestClient -from typing_extensions import Annotated app = FastAPI() diff --git a/tests/test_generate_unique_id_function.py b/tests/test_generate_unique_id_function.py index 5aeec66367..62ebfbc964 100644 --- a/tests/test_generate_unique_id_function.py +++ b/tests/test_generate_unique_id_function.py @@ -1,5 +1,4 @@ import warnings -from typing import List from fastapi import APIRouter, FastAPI from fastapi.routing import APIRoute @@ -33,12 +32,12 @@ def test_top_level_generate_unique_id(): app = FastAPI(generate_unique_id_function=custom_generate_unique_id) router = APIRouter() - @app.post("/", response_model=List[Item], responses={404: {"model": List[Message]}}) + @app.post("/", response_model=list[Item], responses={404: {"model": list[Message]}}) def post_root(item1: Item, item2: Item): return item1, item2 # pragma: nocover @router.post( - "/router", response_model=List[Item], responses={404: {"model": List[Message]}} + "/router", response_model=list[Item], responses={404: {"model": list[Message]}} ) def post_router(item1: Item, item2: Item): return item1, item2 # pragma: nocover @@ -234,12 +233,12 @@ def test_router_overrides_generate_unique_id(): app = FastAPI(generate_unique_id_function=custom_generate_unique_id) router = APIRouter(generate_unique_id_function=custom_generate_unique_id2) - @app.post("/", response_model=List[Item], responses={404: {"model": List[Message]}}) + @app.post("/", response_model=list[Item], responses={404: {"model": list[Message]}}) def post_root(item1: Item, item2: Item): return item1, item2 # pragma: nocover @router.post( - "/router", response_model=List[Item], responses={404: {"model": List[Message]}} + "/router", response_model=list[Item], responses={404: {"model": list[Message]}} ) def post_router(item1: Item, item2: Item): return item1, item2 # pragma: nocover @@ -435,12 +434,12 @@ def test_router_include_overrides_generate_unique_id(): app = FastAPI(generate_unique_id_function=custom_generate_unique_id) router = APIRouter(generate_unique_id_function=custom_generate_unique_id2) - @app.post("/", response_model=List[Item], responses={404: {"model": List[Message]}}) + @app.post("/", response_model=list[Item], responses={404: {"model": list[Message]}}) def post_root(item1: Item, item2: Item): return item1, item2 # pragma: nocover @router.post( - "/router", response_model=List[Item], responses={404: {"model": List[Message]}} + "/router", response_model=list[Item], responses={404: {"model": list[Message]}} ) def post_router(item1: Item, item2: Item): return item1, item2 # pragma: nocover @@ -637,20 +636,20 @@ def test_subrouter_top_level_include_overrides_generate_unique_id(): router = APIRouter() sub_router = APIRouter(generate_unique_id_function=custom_generate_unique_id2) - @app.post("/", response_model=List[Item], responses={404: {"model": List[Message]}}) + @app.post("/", response_model=list[Item], responses={404: {"model": list[Message]}}) def post_root(item1: Item, item2: Item): return item1, item2 # pragma: nocover @router.post( - "/router", response_model=List[Item], responses={404: {"model": List[Message]}} + "/router", response_model=list[Item], responses={404: {"model": list[Message]}} ) def post_router(item1: Item, item2: Item): return item1, item2 # pragma: nocover @sub_router.post( "/subrouter", - response_model=List[Item], - responses={404: {"model": List[Message]}}, + response_model=list[Item], + responses={404: {"model": list[Message]}}, ) def post_subrouter(item1: Item, item2: Item): return item1, item2 # pragma: nocover @@ -910,14 +909,14 @@ def test_router_path_operation_overrides_generate_unique_id(): app = FastAPI(generate_unique_id_function=custom_generate_unique_id) router = APIRouter(generate_unique_id_function=custom_generate_unique_id2) - @app.post("/", response_model=List[Item], responses={404: {"model": List[Message]}}) + @app.post("/", response_model=list[Item], responses={404: {"model": list[Message]}}) def post_root(item1: Item, item2: Item): return item1, item2 # pragma: nocover @router.post( "/router", - response_model=List[Item], - responses={404: {"model": List[Message]}}, + response_model=list[Item], + responses={404: {"model": list[Message]}}, generate_unique_id_function=custom_generate_unique_id3, ) def post_router(item1: Item, item2: Item): @@ -1116,8 +1115,8 @@ def test_app_path_operation_overrides_generate_unique_id(): @app.post( "/", - response_model=List[Item], - responses={404: {"model": List[Message]}}, + response_model=list[Item], + responses={404: {"model": list[Message]}}, generate_unique_id_function=custom_generate_unique_id3, ) def post_root(item1: Item, item2: Item): @@ -1125,8 +1124,8 @@ def test_app_path_operation_overrides_generate_unique_id(): @router.post( "/router", - response_model=List[Item], - responses={404: {"model": List[Message]}}, + response_model=list[Item], + responses={404: {"model": list[Message]}}, ) def post_router(item1: Item, item2: Item): return item1, item2 # pragma: nocover @@ -1324,8 +1323,8 @@ def test_callback_override_generate_unique_id(): @callback_router.post( "/post-callback", - response_model=List[Item], - responses={404: {"model": List[Message]}}, + response_model=list[Item], + responses={404: {"model": list[Message]}}, generate_unique_id_function=custom_generate_unique_id3, ) def post_callback(item1: Item, item2: Item): @@ -1333,8 +1332,8 @@ def test_callback_override_generate_unique_id(): @app.post( "/", - response_model=List[Item], - responses={404: {"model": List[Message]}}, + response_model=list[Item], + responses={404: {"model": list[Message]}}, generate_unique_id_function=custom_generate_unique_id3, callbacks=callback_router.routes, ) @@ -1343,8 +1342,8 @@ def test_callback_override_generate_unique_id(): @app.post( "/tocallback", - response_model=List[Item], - responses={404: {"model": List[Message]}}, + response_model=list[Item], + responses={404: {"model": list[Message]}}, ) def post_with_callback(item1: Item, item2: Item): return item1, item2 # pragma: nocover diff --git a/tests/test_generic_parameterless_depends.py b/tests/test_generic_parameterless_depends.py index 5aa35320c9..93b72ad243 100644 --- a/tests/test_generic_parameterless_depends.py +++ b/tests/test_generic_parameterless_depends.py @@ -1,8 +1,7 @@ -from typing import TypeVar +from typing import Annotated, TypeVar from fastapi import Depends, FastAPI from fastapi.testclient import TestClient -from typing_extensions import Annotated app = FastAPI() diff --git a/tests/test_get_model_definitions_formfeed_escape.py b/tests/test_get_model_definitions_formfeed_escape.py index 6601585ef0..215d06a072 100644 --- a/tests/test_get_model_definitions_formfeed_escape.py +++ b/tests/test_get_model_definitions_formfeed_escape.py @@ -1,4 +1,5 @@ -from typing import Any, Iterator, Set, Type +from collections.abc import Iterator +from typing import Any import fastapi._compat import fastapi.openapi.utils @@ -143,11 +144,11 @@ class SortedTypeSet(set): Set of Types whose `__iter__()` method yields results sorted by the type names """ - def __init__(self, seq: Set[Type[Any]], *, sort_reversed: bool): + def __init__(self, seq: set[type[Any]], *, sort_reversed: bool): super().__init__(seq) self.sort_reversed = sort_reversed - def __iter__(self) -> Iterator[Type[Any]]: + def __iter__(self) -> Iterator[type[Any]]: members_sorted = sorted( super().__iter__(), key=lambda type_: type_.__name__, diff --git a/tests/test_invalid_path_param.py b/tests/test_invalid_path_param.py index d5fa53c1fc..35c00363da 100644 --- a/tests/test_invalid_path_param.py +++ b/tests/test_invalid_path_param.py @@ -1,5 +1,3 @@ -from typing import Dict, List, Tuple - import pytest from fastapi import FastAPI from pydantic import BaseModel @@ -13,7 +11,7 @@ def test_invalid_sequence(): title: str @app.get("/items/{id}") - def read_items(id: List[Item]): + def read_items(id: list[Item]): pass # pragma: no cover @@ -25,7 +23,7 @@ def test_invalid_tuple(): title: str @app.get("/items/{id}") - def read_items(id: Tuple[Item, Item]): + def read_items(id: tuple[Item, Item]): pass # pragma: no cover @@ -37,7 +35,7 @@ def test_invalid_dict(): title: str @app.get("/items/{id}") - def read_items(id: Dict[str, Item]): + def read_items(id: dict[str, Item]): pass # pragma: no cover diff --git a/tests/test_invalid_sequence_param.py b/tests/test_invalid_sequence_param.py index 475786adbf..2b8fd059e1 100644 --- a/tests/test_invalid_sequence_param.py +++ b/tests/test_invalid_sequence_param.py @@ -1,4 +1,4 @@ -from typing import Dict, List, Optional, Tuple +from typing import Optional import pytest from fastapi import FastAPI, Query @@ -13,7 +13,7 @@ def test_invalid_sequence(): title: str @app.get("/items/") - def read_items(q: List[Item] = Query(default=None)): + def read_items(q: list[Item] = Query(default=None)): pass # pragma: no cover @@ -25,7 +25,7 @@ def test_invalid_tuple(): title: str @app.get("/items/") - def read_items(q: Tuple[Item, Item] = Query(default=None)): + def read_items(q: tuple[Item, Item] = Query(default=None)): pass # pragma: no cover @@ -37,7 +37,7 @@ def test_invalid_dict(): title: str @app.get("/items/") - def read_items(q: Dict[str, Item] = Query(default=None)): + def read_items(q: dict[str, Item] = Query(default=None)): pass # pragma: no cover diff --git a/tests/test_multi_body_errors.py b/tests/test_multi_body_errors.py index 33304827a9..6ea405fe70 100644 --- a/tests/test_multi_body_errors.py +++ b/tests/test_multi_body_errors.py @@ -1,5 +1,4 @@ from decimal import Decimal -from typing import List from dirty_equals import IsDict, IsOneOf from fastapi import FastAPI @@ -15,7 +14,7 @@ class Item(BaseModel): @app.post("/items/") -def save_item_no_body(item: List[Item]): +def save_item_no_body(item: list[Item]): return {"item": item} diff --git a/tests/test_multi_query_errors.py b/tests/test_multi_query_errors.py index 8162d986c5..7387a81ddf 100644 --- a/tests/test_multi_query_errors.py +++ b/tests/test_multi_query_errors.py @@ -1,5 +1,3 @@ -from typing import List - from dirty_equals import IsDict from fastapi import FastAPI, Query from fastapi.testclient import TestClient @@ -8,7 +6,7 @@ app = FastAPI() @app.get("/items/") -def read_items(q: List[int] = Query(default=None)): +def read_items(q: list[int] = Query(default=None)): return {"q": q} diff --git a/tests/test_no_schema_split.py b/tests/test_no_schema_split.py index b0b5958c1b..6169867ba3 100644 --- a/tests/test_no_schema_split.py +++ b/tests/test_no_schema_split.py @@ -3,7 +3,6 @@ # 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 @@ -25,7 +24,7 @@ class MessageEvent(BaseModel): class MessageOutput(BaseModel): body: str = "" - events: List[MessageEvent] = [] + events: list[MessageEvent] = [] class Message(BaseModel): diff --git a/tests/test_openapi_schema_type.py b/tests/test_openapi_schema_type.py index a45ea20c8c..98d9787455 100644 --- a/tests/test_openapi_schema_type.py +++ b/tests/test_openapi_schema_type.py @@ -1,4 +1,4 @@ -from typing import List, Optional, Union +from typing import Optional, Union import pytest from fastapi.openapi.models import Schema, SchemaType @@ -13,7 +13,7 @@ from fastapi.openapi.models import Schema, SchemaType ], ) def test_allowed_schema_type( - type_value: Optional[Union[SchemaType, List[SchemaType]]], + type_value: Optional[Union[SchemaType, list[SchemaType]]], ) -> None: """Test that Schema accepts SchemaType, List[SchemaType] and None for type field.""" schema = Schema(type=type_value) diff --git a/tests/test_openapi_separate_input_output_schemas.py b/tests/test_openapi_separate_input_output_schemas.py index c9a05418bf..bfe5e9a712 100644 --- a/tests/test_openapi_separate_input_output_schemas.py +++ b/tests/test_openapi_separate_input_output_schemas.py @@ -1,4 +1,4 @@ -from typing import List, Optional +from typing import Optional from fastapi import FastAPI from fastapi.testclient import TestClient @@ -11,7 +11,7 @@ from .utils import PYDANTIC_V2, needs_pydanticv2 class SubItem(BaseModel): subname: str sub_description: Optional[str] = None - tags: List[str] = [] + tags: list[str] = [] if PYDANTIC_V2: model_config = {"json_schema_serialization_defaults_required": True} @@ -44,11 +44,11 @@ def get_app_client(separate_input_output_schemas: bool = True) -> TestClient: return item @app.post("/items-list/") - def create_item_list(item: List[Item]): + def create_item_list(item: list[Item]): return item @app.get("/items/") - def read_items() -> List[Item]: + def read_items() -> list[Item]: return [ Item( name="Portal Gun", diff --git a/tests/test_optional_file_list.py b/tests/test_optional_file_list.py index 0228900cf6..6860258643 100644 --- a/tests/test_optional_file_list.py +++ b/tests/test_optional_file_list.py @@ -1,4 +1,4 @@ -from typing import List, Optional +from typing import Optional from fastapi import FastAPI, File from fastapi.testclient import TestClient @@ -7,7 +7,7 @@ app = FastAPI() @app.post("/files") -async def upload_files(files: Optional[List[bytes]] = File(None)): +async def upload_files(files: Optional[list[bytes]] = File(None)): if files is None: return {"files_count": 0} return {"files_count": len(files), "sizes": [len(f) for f in files]} diff --git a/tests/test_params_repr.py b/tests/test_params_repr.py index baa172497d..19c2e8d696 100644 --- a/tests/test_params_repr.py +++ b/tests/test_params_repr.py @@ -1,9 +1,9 @@ -from typing import Any, List +from typing import Any from dirty_equals import IsOneOf from fastapi.params import Body, Cookie, Header, Param, Path, Query -test_data: List[Any] = ["teststr", None, ..., 1, []] +test_data: list[Any] = ["teststr", None, ..., 1, []] def get_user(): diff --git a/tests/test_pydantic_v1_v2_01.py b/tests/test_pydantic_v1_v2_01.py index 769e5fab62..ebf86b99f0 100644 --- a/tests/test_pydantic_v1_v2_01.py +++ b/tests/test_pydantic_v1_v2_01.py @@ -1,5 +1,5 @@ import sys -from typing import Any, List, Union +from typing import Any, Union from tests.utils import pydantic_snapshot, skip_module_if_py_gte_314 @@ -21,7 +21,7 @@ class Item(BaseModel): size: int description: Union[str, None] = None sub: SubItem - multi: List[SubItem] = [] + multi: list[SubItem] = [] app = FastAPI() diff --git a/tests/test_pydantic_v1_v2_list.py b/tests/test_pydantic_v1_v2_list.py index 64f3dd3446..8879b010de 100644 --- a/tests/test_pydantic_v1_v2_list.py +++ b/tests/test_pydantic_v1_v2_list.py @@ -1,5 +1,5 @@ import sys -from typing import Any, List, Union +from typing import Any, Union from tests.utils import pydantic_snapshot, skip_module_if_py_gte_314 @@ -21,18 +21,18 @@ class Item(BaseModel): size: int description: Union[str, None] = None sub: SubItem - multi: List[SubItem] = [] + multi: list[SubItem] = [] app = FastAPI() @app.post("/item") -def handle_item(data: Item) -> List[Item]: +def handle_item(data: Item) -> list[Item]: return [data, data] -@app.post("/item-filter", response_model=List[Item]) +@app.post("/item-filter", response_model=list[Item]) def handle_item_filter(data: Item) -> Any: extended_data = data.dict() extended_data.update({"secret_data": "classified", "internal_id": 12345}) @@ -41,14 +41,14 @@ def handle_item_filter(data: Item) -> Any: @app.post("/item-list") -def handle_item_list(data: List[Item]) -> Item: +def handle_item_list(data: list[Item]) -> Item: if data: return data[0] return Item(title="", size=0, sub=SubItem(name="")) @app.post("/item-list-filter", response_model=Item) -def handle_item_list_filter(data: List[Item]) -> Any: +def handle_item_list_filter(data: list[Item]) -> Any: if data: extended_data = data[0].dict() extended_data.update({"secret_data": "classified", "internal_id": 12345}) @@ -58,12 +58,12 @@ def handle_item_list_filter(data: List[Item]) -> Any: @app.post("/item-list-to-list") -def handle_item_list_to_list(data: List[Item]) -> List[Item]: +def handle_item_list_to_list(data: list[Item]) -> list[Item]: return data -@app.post("/item-list-to-list-filter", response_model=List[Item]) -def handle_item_list_to_list_filter(data: List[Item]) -> Any: +@app.post("/item-list-to-list-filter", response_model=list[Item]) +def handle_item_list_to_list_filter(data: list[Item]) -> Any: if data: extended_data = data[0].dict() extended_data.update({"secret_data": "classified", "internal_id": 12345}) diff --git a/tests/test_pydantic_v1_v2_mixed.py b/tests/test_pydantic_v1_v2_mixed.py index 54d408827f..e66583cd54 100644 --- a/tests/test_pydantic_v1_v2_mixed.py +++ b/tests/test_pydantic_v1_v2_mixed.py @@ -1,5 +1,5 @@ import sys -from typing import Any, List, Union +from typing import Any, Union from tests.utils import pydantic_snapshot, skip_module_if_py_gte_314 @@ -22,7 +22,7 @@ class Item(BaseModel): size: int description: Union[str, None] = None sub: SubItem - multi: List[SubItem] = [] + multi: list[SubItem] = [] class NewSubItem(NewBaseModel): @@ -34,7 +34,7 @@ class NewItem(NewBaseModel): new_size: int new_description: Union[str, None] = None new_sub: NewSubItem - new_multi: List[NewSubItem] = [] + new_multi: list[NewSubItem] = [] app = FastAPI() @@ -93,7 +93,7 @@ def handle_v2_item_to_v1_filter(data: NewItem) -> Any: @app.post("/v1-to-v2/item-to-list") -def handle_v1_item_to_v2_list(data: Item) -> List[NewItem]: +def handle_v1_item_to_v2_list(data: Item) -> list[NewItem]: converted = NewItem( new_title=data.title, new_size=data.size, @@ -105,7 +105,7 @@ def handle_v1_item_to_v2_list(data: Item) -> List[NewItem]: @app.post("/v1-to-v2/list-to-list") -def handle_v1_list_to_v2_list(data: List[Item]) -> List[NewItem]: +def handle_v1_list_to_v2_list(data: list[Item]) -> list[NewItem]: result = [] for item in data: result.append( @@ -120,8 +120,8 @@ def handle_v1_list_to_v2_list(data: List[Item]) -> List[NewItem]: return result -@app.post("/v1-to-v2/list-to-list-filter", response_model=List[NewItem]) -def handle_v1_list_to_v2_list_filter(data: List[Item]) -> Any: +@app.post("/v1-to-v2/list-to-list-filter", response_model=list[NewItem]) +def handle_v1_list_to_v2_list_filter(data: list[Item]) -> Any: result = [] for item in data: converted = { @@ -140,7 +140,7 @@ def handle_v1_list_to_v2_list_filter(data: List[Item]) -> Any: @app.post("/v1-to-v2/list-to-item") -def handle_v1_list_to_v2_item(data: List[Item]) -> NewItem: +def handle_v1_list_to_v2_item(data: list[Item]) -> NewItem: if data: item = data[0] return NewItem( @@ -154,7 +154,7 @@ def handle_v1_list_to_v2_item(data: List[Item]) -> NewItem: @app.post("/v2-to-v1/item-to-list") -def handle_v2_item_to_v1_list(data: NewItem) -> List[Item]: +def handle_v2_item_to_v1_list(data: NewItem) -> list[Item]: converted = Item( title=data.new_title, size=data.new_size, @@ -166,7 +166,7 @@ def handle_v2_item_to_v1_list(data: NewItem) -> List[Item]: @app.post("/v2-to-v1/list-to-list") -def handle_v2_list_to_v1_list(data: List[NewItem]) -> List[Item]: +def handle_v2_list_to_v1_list(data: list[NewItem]) -> list[Item]: result = [] for item in data: result.append( @@ -181,8 +181,8 @@ def handle_v2_list_to_v1_list(data: List[NewItem]) -> List[Item]: return result -@app.post("/v2-to-v1/list-to-list-filter", response_model=List[Item]) -def handle_v2_list_to_v1_list_filter(data: List[NewItem]) -> Any: +@app.post("/v2-to-v1/list-to-list-filter", response_model=list[Item]) +def handle_v2_list_to_v1_list_filter(data: list[NewItem]) -> Any: result = [] for item in data: converted = { @@ -201,7 +201,7 @@ def handle_v2_list_to_v1_list_filter(data: List[NewItem]) -> Any: @app.post("/v2-to-v1/list-to-item") -def handle_v2_list_to_v1_item(data: List[NewItem]) -> Item: +def handle_v2_list_to_v1_item(data: list[NewItem]) -> Item: if data: item = data[0] return Item( diff --git a/tests/test_pydantic_v1_v2_multifile/main.py b/tests/test_pydantic_v1_v2_multifile/main.py index 8985cb7b4c..9397368abf 100644 --- a/tests/test_pydantic_v1_v2_multifile/main.py +++ b/tests/test_pydantic_v1_v2_multifile/main.py @@ -1,5 +1,3 @@ -from typing import List - from fastapi import FastAPI from . import modelsv1, modelsv2, modelsv2b @@ -30,7 +28,7 @@ def handle_v2_item_to_v1(data: modelsv2.Item) -> modelsv1.Item: @app.post("/v1-to-v2/item-to-list") -def handle_v1_item_to_v2_list(data: modelsv1.Item) -> List[modelsv2.Item]: +def handle_v1_item_to_v2_list(data: modelsv1.Item) -> list[modelsv2.Item]: converted = modelsv2.Item( new_title=data.title, new_size=data.size, @@ -42,7 +40,7 @@ def handle_v1_item_to_v2_list(data: modelsv1.Item) -> List[modelsv2.Item]: @app.post("/v1-to-v2/list-to-list") -def handle_v1_list_to_v2_list(data: List[modelsv1.Item]) -> List[modelsv2.Item]: +def handle_v1_list_to_v2_list(data: list[modelsv1.Item]) -> list[modelsv2.Item]: result = [] for item in data: result.append( @@ -58,7 +56,7 @@ def handle_v1_list_to_v2_list(data: List[modelsv1.Item]) -> List[modelsv2.Item]: @app.post("/v1-to-v2/list-to-item") -def handle_v1_list_to_v2_item(data: List[modelsv1.Item]) -> modelsv2.Item: +def handle_v1_list_to_v2_item(data: list[modelsv1.Item]) -> modelsv2.Item: if data: item = data[0] return modelsv2.Item( @@ -74,7 +72,7 @@ def handle_v1_list_to_v2_item(data: List[modelsv1.Item]) -> modelsv2.Item: @app.post("/v2-to-v1/item-to-list") -def handle_v2_item_to_v1_list(data: modelsv2.Item) -> List[modelsv1.Item]: +def handle_v2_item_to_v1_list(data: modelsv2.Item) -> list[modelsv1.Item]: converted = modelsv1.Item( title=data.new_title, size=data.new_size, @@ -86,7 +84,7 @@ def handle_v2_item_to_v1_list(data: modelsv2.Item) -> List[modelsv1.Item]: @app.post("/v2-to-v1/list-to-list") -def handle_v2_list_to_v1_list(data: List[modelsv2.Item]) -> List[modelsv1.Item]: +def handle_v2_list_to_v1_list(data: list[modelsv2.Item]) -> list[modelsv1.Item]: result = [] for item in data: result.append( @@ -102,7 +100,7 @@ def handle_v2_list_to_v1_list(data: List[modelsv2.Item]) -> List[modelsv1.Item]: @app.post("/v2-to-v1/list-to-item") -def handle_v2_list_to_v1_item(data: List[modelsv2.Item]) -> modelsv1.Item: +def handle_v2_list_to_v1_item(data: list[modelsv2.Item]) -> modelsv1.Item: if data: item = data[0] return modelsv1.Item( @@ -130,8 +128,8 @@ def handle_v2_same_name_to_v1( @app.post("/v2-to-v1/list-of-items-to-list-of-items") def handle_v2_items_in_list_to_v1_item_in_list( - data1: List[modelsv2.ItemInList], data2: List[modelsv2b.ItemInList] -) -> List[modelsv1.ItemInList]: + data1: list[modelsv2.ItemInList], data2: list[modelsv2b.ItemInList] +) -> list[modelsv1.ItemInList]: result = [] item1 = data1[0] item2 = data2[0] diff --git a/tests/test_pydantic_v1_v2_multifile/modelsv1.py b/tests/test_pydantic_v1_v2_multifile/modelsv1.py index 889291a1a7..0cc8de4559 100644 --- a/tests/test_pydantic_v1_v2_multifile/modelsv1.py +++ b/tests/test_pydantic_v1_v2_multifile/modelsv1.py @@ -1,4 +1,4 @@ -from typing import List, Union +from typing import Union from fastapi._compat.v1 import BaseModel @@ -12,7 +12,7 @@ class Item(BaseModel): size: int description: Union[str, None] = None sub: SubItem - multi: List[SubItem] = [] + multi: list[SubItem] = [] class ItemInList(BaseModel): diff --git a/tests/test_pydantic_v1_v2_multifile/modelsv2.py b/tests/test_pydantic_v1_v2_multifile/modelsv2.py index 2c8c6ea356..d80b77e103 100644 --- a/tests/test_pydantic_v1_v2_multifile/modelsv2.py +++ b/tests/test_pydantic_v1_v2_multifile/modelsv2.py @@ -1,4 +1,4 @@ -from typing import List, Union +from typing import Union from pydantic import BaseModel @@ -12,7 +12,7 @@ class Item(BaseModel): new_size: int new_description: Union[str, None] = None new_sub: SubItem - new_multi: List[SubItem] = [] + new_multi: list[SubItem] = [] class ItemInList(BaseModel): diff --git a/tests/test_pydantic_v1_v2_multifile/modelsv2b.py b/tests/test_pydantic_v1_v2_multifile/modelsv2b.py index dc0c06c669..e992bea2e1 100644 --- a/tests/test_pydantic_v1_v2_multifile/modelsv2b.py +++ b/tests/test_pydantic_v1_v2_multifile/modelsv2b.py @@ -1,4 +1,4 @@ -from typing import List, Union +from typing import Union from pydantic import BaseModel @@ -12,7 +12,7 @@ class Item(BaseModel): dup_size: int dup_description: Union[str, None] = None dup_sub: SubItem - dup_multi: List[SubItem] = [] + dup_multi: list[SubItem] = [] class ItemInList(BaseModel): diff --git a/tests/test_pydantic_v1_v2_noneable.py b/tests/test_pydantic_v1_v2_noneable.py index d2d6f6635b..3e86469908 100644 --- a/tests/test_pydantic_v1_v2_noneable.py +++ b/tests/test_pydantic_v1_v2_noneable.py @@ -1,5 +1,5 @@ import sys -from typing import Any, List, Union +from typing import Any, Union from tests.utils import pydantic_snapshot, skip_module_if_py_gte_314 @@ -22,7 +22,7 @@ class Item(BaseModel): size: int description: Union[str, None] = None sub: SubItem - multi: List[SubItem] = [] + multi: list[SubItem] = [] class NewSubItem(NewBaseModel): @@ -34,7 +34,7 @@ class NewItem(NewBaseModel): new_size: int new_description: Union[str, None] = None new_sub: NewSubItem - new_multi: List[NewSubItem] = [] + new_multi: list[NewSubItem] = [] app = FastAPI() diff --git a/tests/test_pydanticv2_dataclasses_uuid_stringified_annotations.py b/tests/test_pydanticv2_dataclasses_uuid_stringified_annotations.py index c9f94563bb..b72b0518a1 100644 --- a/tests/test_pydanticv2_dataclasses_uuid_stringified_annotations.py +++ b/tests/test_pydanticv2_dataclasses_uuid_stringified_annotations.py @@ -2,7 +2,7 @@ from __future__ import annotations import uuid from dataclasses import dataclass, field -from typing import List, Union +from typing import Union from dirty_equals import IsUUID from fastapi import FastAPI @@ -15,7 +15,7 @@ class Item: id: uuid.UUID name: str price: float - tags: List[str] = field(default_factory=list) + tags: list[str] = field(default_factory=list) description: Union[str, None] = None tax: Union[float, None] = None diff --git a/tests/test_regex_deprecated_body.py b/tests/test_regex_deprecated_body.py index 74654ff3ce..cfbff19c87 100644 --- a/tests/test_regex_deprecated_body.py +++ b/tests/test_regex_deprecated_body.py @@ -1,8 +1,9 @@ +from typing import Annotated + import pytest from dirty_equals import IsDict from fastapi import FastAPI, Form from fastapi.testclient import TestClient -from typing_extensions import Annotated from .utils import needs_py310 diff --git a/tests/test_regex_deprecated_params.py b/tests/test_regex_deprecated_params.py index 2ce64c6862..7d9988f9f8 100644 --- a/tests/test_regex_deprecated_params.py +++ b/tests/test_regex_deprecated_params.py @@ -1,8 +1,9 @@ +from typing import Annotated + import pytest from dirty_equals import IsDict from fastapi import FastAPI, Query from fastapi.testclient import TestClient -from typing_extensions import Annotated from .utils import needs_py310 diff --git a/tests/test_request_body_parameters_media_type.py b/tests/test_request_body_parameters_media_type.py index 8c72fee54a..d1bff9ddf4 100644 --- a/tests/test_request_body_parameters_media_type.py +++ b/tests/test_request_body_parameters_media_type.py @@ -1,5 +1,3 @@ -import typing - from fastapi import Body, FastAPI from fastapi.testclient import TestClient from pydantic import BaseModel @@ -28,7 +26,7 @@ async def create_product(data: Product = Body(media_type=media_type, embed=True) @app.post("/shops") async def create_shop( data: Shop = Body(media_type=media_type), - included: typing.List[Product] = Body(default=[], media_type=media_type), + included: list[Product] = Body(default=[], media_type=media_type), ): pass # pragma: no cover diff --git a/tests/test_request_params/test_body/test_list.py b/tests/test_request_params/test_body/test_list.py index 18a2a2f308..b2503a1c44 100644 --- a/tests/test_request_params/test_body/test_list.py +++ b/tests/test_request_params/test_body/test_list.py @@ -1,11 +1,10 @@ -from typing import List, Union +from typing import Annotated, Union import pytest from dirty_equals import IsDict, IsOneOf, IsPartialDict from fastapi import Body, FastAPI from fastapi.testclient import TestClient from pydantic import BaseModel, Field -from typing_extensions import Annotated from tests.utils import needs_pydanticv2 @@ -18,12 +17,12 @@ app = FastAPI() @app.post("/required-list-str", operation_id="required_list_str") -async def read_required_list_str(p: Annotated[List[str], Body(embed=True)]): +async def read_required_list_str(p: Annotated[list[str], Body(embed=True)]): return {"p": p} class BodyModelRequiredListStr(BaseModel): - p: List[str] + p: list[str] @app.post("/model-required-list-str", operation_id="model_required_list_str") @@ -103,13 +102,13 @@ def test_required_list_str(path: str): @app.post("/required-list-alias", operation_id="required_list_alias") async def read_required_list_alias( - p: Annotated[List[str], Body(embed=True, alias="p_alias")], + p: Annotated[list[str], Body(embed=True, alias="p_alias")], ): return {"p": p} class BodyModelRequiredListAlias(BaseModel): - p: List[str] = Field(alias="p_alias") + p: list[str] = Field(alias="p_alias") @app.post("/model-required-list-alias", operation_id="model_required_list_alias") @@ -228,13 +227,13 @@ def test_required_list_alias_by_alias(path: str): "/required-list-validation-alias", operation_id="required_list_validation_alias" ) def read_required_list_validation_alias( - p: Annotated[List[str], Body(embed=True, validation_alias="p_val_alias")], + p: Annotated[list[str], Body(embed=True, validation_alias="p_val_alias")], ): return {"p": p} class BodyModelRequiredListValidationAlias(BaseModel): - p: List[str] = Field(validation_alias="p_val_alias") + p: list[str] = Field(validation_alias="p_val_alias") @app.post( @@ -345,14 +344,14 @@ def test_required_list_validation_alias_by_validation_alias(path: str): ) def read_required_list_alias_and_validation_alias( p: Annotated[ - List[str], Body(embed=True, alias="p_alias", validation_alias="p_val_alias") + list[str], Body(embed=True, alias="p_alias", validation_alias="p_val_alias") ], ): return {"p": p} class BodyModelRequiredListAliasAndValidationAlias(BaseModel): - p: List[str] = Field(alias="p_alias", validation_alias="p_val_alias") + p: list[str] = Field(alias="p_alias", validation_alias="p_val_alias") @app.post( diff --git a/tests/test_request_params/test_body/test_optional_list.py b/tests/test_request_params/test_body/test_optional_list.py index e2ecdc7f43..ede635f840 100644 --- a/tests/test_request_params/test_body/test_optional_list.py +++ b/tests/test_request_params/test_body/test_optional_list.py @@ -1,11 +1,10 @@ -from typing import List, Optional +from typing import Annotated, Optional import pytest from dirty_equals import IsDict from fastapi import Body, FastAPI from fastapi.testclient import TestClient from pydantic import BaseModel, Field -from typing_extensions import Annotated from tests.utils import needs_pydanticv2 @@ -19,13 +18,13 @@ app = FastAPI() @app.post("/optional-list-str", operation_id="optional_list_str") async def read_optional_list_str( - p: Annotated[Optional[List[str]], Body(embed=True)] = None, + p: Annotated[Optional[list[str]], Body(embed=True)] = None, ): return {"p": p} class BodyModelOptionalListStr(BaseModel): - p: Optional[List[str]] = None + p: Optional[list[str]] = None @app.post("/model-optional-list-str", operation_id="model_optional_list_str") @@ -131,13 +130,13 @@ def test_optional_list_str(path: str): @app.post("/optional-list-alias", operation_id="optional_list_alias") async def read_optional_list_alias( - p: Annotated[Optional[List[str]], Body(embed=True, alias="p_alias")] = None, + p: Annotated[Optional[list[str]], Body(embed=True, alias="p_alias")] = None, ): return {"p": p} class BodyModelOptionalListAlias(BaseModel): - p: Optional[List[str]] = Field(None, alias="p_alias") + p: Optional[list[str]] = Field(None, alias="p_alias") @app.post("/model-optional-list-alias", operation_id="model_optional_list_alias") @@ -264,14 +263,14 @@ def test_optional_list_alias_by_alias(path: str): ) def read_optional_list_validation_alias( p: Annotated[ - Optional[List[str]], Body(embed=True, validation_alias="p_val_alias") + Optional[list[str]], Body(embed=True, validation_alias="p_val_alias") ] = None, ): return {"p": p} class BodyModelOptionalListValidationAlias(BaseModel): - p: Optional[List[str]] = Field(None, validation_alias="p_val_alias") + p: Optional[list[str]] = Field(None, validation_alias="p_val_alias") @app.post( @@ -410,7 +409,7 @@ def test_optional_list_validation_alias_by_validation_alias(path: str): ) def read_optional_list_alias_and_validation_alias( p: Annotated[ - Optional[List[str]], + Optional[list[str]], Body(embed=True, alias="p_alias", validation_alias="p_val_alias"), ] = None, ): @@ -418,7 +417,7 @@ def read_optional_list_alias_and_validation_alias( class BodyModelOptionalListAliasAndValidationAlias(BaseModel): - p: Optional[List[str]] = Field( + p: Optional[list[str]] = Field( None, alias="p_alias", validation_alias="p_val_alias" ) diff --git a/tests/test_request_params/test_body/test_optional_str.py b/tests/test_request_params/test_body/test_optional_str.py index a49f5a3675..9e0c7217cc 100644 --- a/tests/test_request_params/test_body/test_optional_str.py +++ b/tests/test_request_params/test_body/test_optional_str.py @@ -1,11 +1,10 @@ -from typing import Optional +from typing import Annotated, Optional import pytest from dirty_equals import IsDict from fastapi import Body, FastAPI from fastapi.testclient import TestClient from pydantic import BaseModel, Field -from typing_extensions import Annotated from tests.utils import needs_pydanticv2 diff --git a/tests/test_request_params/test_body/test_required_str.py b/tests/test_request_params/test_body/test_required_str.py index 18c660cad2..aa47a4ede3 100644 --- a/tests/test_request_params/test_body/test_required_str.py +++ b/tests/test_request_params/test_body/test_required_str.py @@ -1,11 +1,10 @@ -from typing import Any, Dict, Union +from typing import Annotated, Any, Union import pytest from dirty_equals import IsDict, IsOneOf from fastapi import Body, FastAPI from fastapi.testclient import TestClient from pydantic import BaseModel, Field -from typing_extensions import Annotated from tests.utils import needs_pydanticv2 @@ -54,7 +53,7 @@ def test_required_str_schema(path: str): "path", ["/required-str", "/model-required-str"], ) -def test_required_str_missing(path: str, json: Union[Dict[str, Any], None]): +def test_required_str_missing(path: str, json: Union[dict[str, Any], None]): client = TestClient(app) response = client.post(path, json=json) assert response.status_code == 422 @@ -140,7 +139,7 @@ def test_required_str_alias_schema(path: str): "path", ["/required-alias", "/model-required-alias"], ) -def test_required_alias_missing(path: str, json: Union[Dict[str, Any], None]): +def test_required_alias_missing(path: str, json: Union[dict[str, Any], None]): client = TestClient(app) response = client.post(path, json=json) assert response.status_code == 422 @@ -266,7 +265,7 @@ def test_required_validation_alias_schema(path: str): ], ) def test_required_validation_alias_missing( - path: str, json: Union[Dict[str, Any], None] + path: str, json: Union[dict[str, Any], None] ): client = TestClient(app) response = client.post(path, json=json) @@ -386,7 +385,7 @@ def test_required_alias_and_validation_alias_schema(path: str): ], ) def test_required_alias_and_validation_alias_missing( - path: str, json: Union[Dict[str, Any], None] + path: str, json: Union[dict[str, Any], None] ): client = TestClient(app) response = client.post(path, json=json) diff --git a/tests/test_request_params/test_body/utils.py b/tests/test_request_params/test_body/utils.py index 5151a82d36..bf07394f90 100644 --- a/tests/test_request_params/test_body/utils.py +++ b/tests/test_request_params/test_body/utils.py @@ -1,7 +1,7 @@ -from typing import Any, Dict +from typing import Any -def get_body_model_name(openapi: Dict[str, Any], path: str) -> str: +def get_body_model_name(openapi: dict[str, Any], path: str) -> str: body = openapi["paths"][path]["post"]["requestBody"] body_schema = body["content"]["application/json"]["schema"] return body_schema.get("$ref", "").split("/")[-1] diff --git a/tests/test_request_params/test_cookie/test_optional_str.py b/tests/test_request_params/test_cookie/test_optional_str.py index 1eec45689d..f2d02dae54 100644 --- a/tests/test_request_params/test_cookie/test_optional_str.py +++ b/tests/test_request_params/test_cookie/test_optional_str.py @@ -1,11 +1,10 @@ -from typing import Optional +from typing import Annotated, Optional import pytest from dirty_equals import IsDict from fastapi import Cookie, FastAPI from fastapi.testclient import TestClient from pydantic import BaseModel, Field -from typing_extensions import Annotated from tests.utils import needs_pydanticv2 diff --git a/tests/test_request_params/test_cookie/test_required_str.py b/tests/test_request_params/test_cookie/test_required_str.py index 6d0fa2ef29..3255857d44 100644 --- a/tests/test_request_params/test_cookie/test_required_str.py +++ b/tests/test_request_params/test_cookie/test_required_str.py @@ -1,9 +1,10 @@ +from typing import Annotated + import pytest from dirty_equals import IsDict, IsOneOf from fastapi import Cookie, FastAPI from fastapi.testclient import TestClient from pydantic import BaseModel, Field -from typing_extensions import Annotated from tests.utils import needs_pydanticv2 diff --git a/tests/test_request_params/test_file/test_list.py b/tests/test_request_params/test_file/test_list.py index 94a33967f3..52b032e441 100644 --- a/tests/test_request_params/test_file/test_list.py +++ b/tests/test_request_params/test_file/test_list.py @@ -1,10 +1,9 @@ -from typing import List +from typing import Annotated import pytest from dirty_equals import IsDict from fastapi import FastAPI, File, UploadFile from fastapi.testclient import TestClient -from typing_extensions import Annotated from tests.utils import needs_pydanticv2 @@ -17,12 +16,12 @@ app = FastAPI() @app.post("/list-bytes", operation_id="list_bytes") -async def read_list_bytes(p: Annotated[List[bytes], File()]): +async def read_list_bytes(p: Annotated[list[bytes], File()]): return {"file_size": [len(file) for file in p]} @app.post("/list-uploadfile", operation_id="list_uploadfile") -async def read_list_uploadfile(p: Annotated[List[UploadFile], File()]): +async def read_list_uploadfile(p: Annotated[list[UploadFile], File()]): return {"file_size": [file.size for file in p]} @@ -122,13 +121,13 @@ def test_list(path: str): @app.post("/list-bytes-alias", operation_id="list_bytes_alias") -async def read_list_bytes_alias(p: Annotated[List[bytes], File(alias="p_alias")]): +async def read_list_bytes_alias(p: Annotated[list[bytes], File(alias="p_alias")]): return {"file_size": [len(file) for file in p]} @app.post("/list-uploadfile-alias", operation_id="list_uploadfile_alias") async def read_list_uploadfile_alias( - p: Annotated[List[UploadFile], File(alias="p_alias")], + p: Annotated[list[UploadFile], File(alias="p_alias")], ): return {"file_size": [file.size for file in p]} @@ -266,7 +265,7 @@ def test_list_alias_by_alias(path: str): @app.post("/list-bytes-validation-alias", operation_id="list_bytes_validation_alias") def read_list_bytes_validation_alias( - p: Annotated[List[bytes], File(validation_alias="p_val_alias")], + p: Annotated[list[bytes], File(validation_alias="p_val_alias")], ): return {"file_size": [len(file) for file in p]} @@ -276,7 +275,7 @@ def read_list_bytes_validation_alias( operation_id="list_uploadfile_validation_alias", ) def read_list_uploadfile_validation_alias( - p: Annotated[List[UploadFile], File(validation_alias="p_val_alias")], + p: Annotated[list[UploadFile], File(validation_alias="p_val_alias")], ): return {"file_size": [file.size for file in p]} @@ -401,7 +400,7 @@ def test_list_validation_alias_by_validation_alias(path: str): operation_id="list_bytes_alias_and_validation_alias", ) def read_list_bytes_alias_and_validation_alias( - p: Annotated[List[bytes], File(alias="p_alias", validation_alias="p_val_alias")], + p: Annotated[list[bytes], File(alias="p_alias", validation_alias="p_val_alias")], ): return {"file_size": [len(file) for file in p]} @@ -412,7 +411,7 @@ def read_list_bytes_alias_and_validation_alias( ) def read_list_uploadfile_alias_and_validation_alias( p: Annotated[ - List[UploadFile], File(alias="p_alias", validation_alias="p_val_alias") + list[UploadFile], File(alias="p_alias", validation_alias="p_val_alias") ], ): return {"file_size": [file.size for file in p]} diff --git a/tests/test_request_params/test_file/test_optional.py b/tests/test_request_params/test_file/test_optional.py index 2c1ca9530e..b7177e071d 100644 --- a/tests/test_request_params/test_file/test_optional.py +++ b/tests/test_request_params/test_file/test_optional.py @@ -1,10 +1,9 @@ -from typing import Optional +from typing import Annotated, Optional import pytest from dirty_equals import IsDict from fastapi import FastAPI, File, UploadFile from fastapi.testclient import TestClient -from typing_extensions import Annotated from tests.utils import needs_pydanticv2 diff --git a/tests/test_request_params/test_file/test_optional_list.py b/tests/test_request_params/test_file/test_optional_list.py index 20e36501f8..af9fe552c9 100644 --- a/tests/test_request_params/test_file/test_optional_list.py +++ b/tests/test_request_params/test_file/test_optional_list.py @@ -1,10 +1,9 @@ -from typing import List, Optional +from typing import Annotated, Optional import pytest from dirty_equals import IsDict from fastapi import FastAPI, File, UploadFile from fastapi.testclient import TestClient -from typing_extensions import Annotated from tests.utils import needs_pydanticv2 @@ -17,13 +16,13 @@ app = FastAPI() @app.post("/optional-list-bytes") -async def read_optional_list_bytes(p: Annotated[Optional[List[bytes]], File()] = None): +async def read_optional_list_bytes(p: Annotated[Optional[list[bytes]], File()] = None): return {"file_size": [len(file) for file in p] if p else None} @app.post("/optional-list-uploadfile") async def read_optional_list_uploadfile( - p: Annotated[Optional[List[UploadFile]], File()] = None, + p: Annotated[Optional[list[UploadFile]], File()] = None, ): return {"file_size": [file.size for file in p] if p else None} @@ -103,14 +102,14 @@ def test_optional_list(path: str): @app.post("/optional-list-bytes-alias") async def read_optional_list_bytes_alias( - p: Annotated[Optional[List[bytes]], File(alias="p_alias")] = None, + p: Annotated[Optional[list[bytes]], File(alias="p_alias")] = None, ): return {"file_size": [len(file) for file in p] if p else None} @app.post("/optional-list-uploadfile-alias") async def read_optional_list_uploadfile_alias( - p: Annotated[Optional[List[UploadFile]], File(alias="p_alias")] = None, + p: Annotated[Optional[list[UploadFile]], File(alias="p_alias")] = None, ): return {"file_size": [file.size for file in p] if p else None} @@ -204,7 +203,7 @@ def test_optional_list_alias_by_alias(path: str): @app.post("/optional-list-bytes-validation-alias") def read_optional_list_bytes_validation_alias( - p: Annotated[Optional[List[bytes]], File(validation_alias="p_val_alias")] = None, + p: Annotated[Optional[list[bytes]], File(validation_alias="p_val_alias")] = None, ): return {"file_size": [len(file) for file in p] if p else None} @@ -212,7 +211,7 @@ def read_optional_list_bytes_validation_alias( @app.post("/optional-list-uploadfile-validation-alias") def read_optional_list_uploadfile_validation_alias( p: Annotated[ - Optional[List[UploadFile]], File(validation_alias="p_val_alias") + Optional[list[UploadFile]], File(validation_alias="p_val_alias") ] = None, ): return {"file_size": [file.size for file in p] if p else None} @@ -314,7 +313,7 @@ def test_optional_validation_alias_by_validation_alias(path: str): @app.post("/optional-list-bytes-alias-and-validation-alias") def read_optional_list_bytes_alias_and_validation_alias( p: Annotated[ - Optional[List[bytes]], File(alias="p_alias", validation_alias="p_val_alias") + Optional[list[bytes]], File(alias="p_alias", validation_alias="p_val_alias") ] = None, ): return {"file_size": [len(file) for file in p] if p else None} @@ -323,7 +322,7 @@ def read_optional_list_bytes_alias_and_validation_alias( @app.post("/optional-list-uploadfile-alias-and-validation-alias") def read_optional_list_uploadfile_alias_and_validation_alias( p: Annotated[ - Optional[List[UploadFile]], + Optional[list[UploadFile]], File(alias="p_alias", validation_alias="p_val_alias"), ] = None, ): diff --git a/tests/test_request_params/test_file/test_required.py b/tests/test_request_params/test_file/test_required.py index f041ac1ccf..2979a1040a 100644 --- a/tests/test_request_params/test_file/test_required.py +++ b/tests/test_request_params/test_file/test_required.py @@ -1,8 +1,9 @@ +from typing import Annotated + import pytest from dirty_equals import IsDict from fastapi import FastAPI, File, UploadFile from fastapi.testclient import TestClient -from typing_extensions import Annotated from tests.utils import needs_pydanticv2 diff --git a/tests/test_request_params/test_file/utils.py b/tests/test_request_params/test_file/utils.py index e33f64385f..e2a97ccd9b 100644 --- a/tests/test_request_params/test_file/utils.py +++ b/tests/test_request_params/test_file/utils.py @@ -1,7 +1,7 @@ -from typing import Any, Dict +from typing import Any -def get_body_model_name(openapi: Dict[str, Any], path: str) -> str: +def get_body_model_name(openapi: dict[str, Any], path: str) -> str: body = openapi["paths"][path]["post"]["requestBody"] body_schema = body["content"]["multipart/form-data"]["schema"] return body_schema.get("$ref", "").split("/")[-1] diff --git a/tests/test_request_params/test_form/test_list.py b/tests/test_request_params/test_form/test_list.py index 69a1b6a380..9f45aa755d 100644 --- a/tests/test_request_params/test_form/test_list.py +++ b/tests/test_request_params/test_form/test_list.py @@ -1,11 +1,10 @@ -from typing import List +from typing import Annotated import pytest from dirty_equals import IsDict, IsOneOf, IsPartialDict from fastapi import FastAPI, Form from fastapi.testclient import TestClient from pydantic import BaseModel, Field -from typing_extensions import Annotated from tests.utils import needs_pydanticv2 @@ -18,12 +17,12 @@ app = FastAPI() @app.post("/required-list-str", operation_id="required_list_str") -async def read_required_list_str(p: Annotated[List[str], Form()]): +async def read_required_list_str(p: Annotated[list[str], Form()]): return {"p": p} class FormModelRequiredListStr(BaseModel): - p: List[str] + p: list[str] @app.post("/model-required-list-str", operation_id="model_required_list_str") @@ -101,12 +100,12 @@ def test_required_list_str(path: str): @app.post("/required-list-alias", operation_id="required_list_alias") -async def read_required_list_alias(p: Annotated[List[str], Form(alias="p_alias")]): +async def read_required_list_alias(p: Annotated[list[str], Form(alias="p_alias")]): return {"p": p} class FormModelRequiredListAlias(BaseModel): - p: List[str] = Field(alias="p_alias") + p: list[str] = Field(alias="p_alias") @app.post("/model-required-list-alias", operation_id="model_required_list_alias") @@ -229,13 +228,13 @@ def test_required_list_alias_by_alias(path: str): "/required-list-validation-alias", operation_id="required_list_validation_alias" ) def read_required_list_validation_alias( - p: Annotated[List[str], Form(validation_alias="p_val_alias")], + p: Annotated[list[str], Form(validation_alias="p_val_alias")], ): return {"p": p} class FormModelRequiredListValidationAlias(BaseModel): - p: List[str] = Field(validation_alias="p_val_alias") + p: list[str] = Field(validation_alias="p_val_alias") @app.post( @@ -345,13 +344,13 @@ def test_required_list_validation_alias_by_validation_alias(path: str): operation_id="required_list_alias_and_validation_alias", ) def read_required_list_alias_and_validation_alias( - p: Annotated[List[str], Form(alias="p_alias", validation_alias="p_val_alias")], + p: Annotated[list[str], Form(alias="p_alias", validation_alias="p_val_alias")], ): return {"p": p} class FormModelRequiredListAliasAndValidationAlias(BaseModel): - p: List[str] = Field(alias="p_alias", validation_alias="p_val_alias") + p: list[str] = Field(alias="p_alias", validation_alias="p_val_alias") @app.post( diff --git a/tests/test_request_params/test_form/test_optional_list.py b/tests/test_request_params/test_form/test_optional_list.py index 1f779a7ed9..0af6d34777 100644 --- a/tests/test_request_params/test_form/test_optional_list.py +++ b/tests/test_request_params/test_form/test_optional_list.py @@ -1,11 +1,10 @@ -from typing import List, Optional +from typing import Annotated, Optional import pytest from dirty_equals import IsDict from fastapi import FastAPI, Form from fastapi.testclient import TestClient from pydantic import BaseModel, Field -from typing_extensions import Annotated from tests.utils import needs_pydanticv2 @@ -19,13 +18,13 @@ app = FastAPI() @app.post("/optional-list-str", operation_id="optional_list_str") async def read_optional_list_str( - p: Annotated[Optional[List[str]], Form()] = None, + p: Annotated[Optional[list[str]], Form()] = None, ): return {"p": p} class FormModelOptionalListStr(BaseModel): - p: Optional[List[str]] = None + p: Optional[list[str]] = None @app.post("/model-optional-list-str", operation_id="model_optional_list_str") @@ -95,13 +94,13 @@ def test_optional_list_str(path: str): @app.post("/optional-list-alias", operation_id="optional_list_alias") async def read_optional_list_alias( - p: Annotated[Optional[List[str]], Form(alias="p_alias")] = None, + p: Annotated[Optional[list[str]], Form(alias="p_alias")] = None, ): return {"p": p} class FormModelOptionalListAlias(BaseModel): - p: Optional[List[str]] = Field(None, alias="p_alias") + p: Optional[list[str]] = Field(None, alias="p_alias") @app.post("/model-optional-list-alias", operation_id="model_optional_list_alias") @@ -193,13 +192,13 @@ def test_optional_list_alias_by_alias(path: str): "/optional-list-validation-alias", operation_id="optional_list_validation_alias" ) def read_optional_list_validation_alias( - p: Annotated[Optional[List[str]], Form(validation_alias="p_val_alias")] = None, + p: Annotated[Optional[list[str]], Form(validation_alias="p_val_alias")] = None, ): return {"p": p} class FormModelOptionalListValidationAlias(BaseModel): - p: Optional[List[str]] = Field(None, validation_alias="p_val_alias") + p: Optional[list[str]] = Field(None, validation_alias="p_val_alias") @app.post( @@ -300,14 +299,14 @@ def test_optional_list_validation_alias_by_validation_alias(path: str): ) def read_optional_list_alias_and_validation_alias( p: Annotated[ - Optional[List[str]], Form(alias="p_alias", validation_alias="p_val_alias") + Optional[list[str]], Form(alias="p_alias", validation_alias="p_val_alias") ] = None, ): return {"p": p} class FormModelOptionalListAliasAndValidationAlias(BaseModel): - p: Optional[List[str]] = Field( + p: Optional[list[str]] = Field( None, alias="p_alias", validation_alias="p_val_alias" ) diff --git a/tests/test_request_params/test_form/test_optional_str.py b/tests/test_request_params/test_form/test_optional_str.py index 9698659452..92329216ec 100644 --- a/tests/test_request_params/test_form/test_optional_str.py +++ b/tests/test_request_params/test_form/test_optional_str.py @@ -1,11 +1,10 @@ -from typing import Optional +from typing import Annotated, Optional import pytest from dirty_equals import IsDict from fastapi import FastAPI, Form from fastapi.testclient import TestClient from pydantic import BaseModel, Field -from typing_extensions import Annotated from tests.utils import needs_pydanticv2 diff --git a/tests/test_request_params/test_form/test_required_str.py b/tests/test_request_params/test_form/test_required_str.py index c901e7b445..1e33038040 100644 --- a/tests/test_request_params/test_form/test_required_str.py +++ b/tests/test_request_params/test_form/test_required_str.py @@ -1,9 +1,10 @@ +from typing import Annotated + import pytest from dirty_equals import IsDict, IsOneOf from fastapi import FastAPI, Form from fastapi.testclient import TestClient from pydantic import BaseModel, Field -from typing_extensions import Annotated from tests.utils import needs_pydanticv2 diff --git a/tests/test_request_params/test_form/utils.py b/tests/test_request_params/test_form/utils.py index d200650dfd..9132173111 100644 --- a/tests/test_request_params/test_form/utils.py +++ b/tests/test_request_params/test_form/utils.py @@ -1,7 +1,7 @@ -from typing import Any, Dict +from typing import Any -def get_body_model_name(openapi: Dict[str, Any], path: str) -> str: +def get_body_model_name(openapi: dict[str, Any], path: str) -> str: body = openapi["paths"][path]["post"]["requestBody"] body_schema = body["content"]["application/x-www-form-urlencoded"]["schema"] return body_schema.get("$ref", "").split("/")[-1] diff --git a/tests/test_request_params/test_header/test_list.py b/tests/test_request_params/test_header/test_list.py index 4a5f4bb647..62f9f36ff6 100644 --- a/tests/test_request_params/test_header/test_list.py +++ b/tests/test_request_params/test_header/test_list.py @@ -1,11 +1,10 @@ -from typing import List +from typing import Annotated import pytest from dirty_equals import AnyThing, IsDict, IsOneOf, IsPartialDict from fastapi import FastAPI, Header from fastapi.testclient import TestClient from pydantic import BaseModel, Field -from typing_extensions import Annotated from tests.utils import needs_pydanticv2 @@ -16,12 +15,12 @@ app = FastAPI() @app.get("/required-list-str") -async def read_required_list_str(p: Annotated[List[str], Header()]): +async def read_required_list_str(p: Annotated[list[str], Header()]): return {"p": p} class HeaderModelRequiredListStr(BaseModel): - p: List[str] + p: list[str] @app.get("/model-required-list-str") @@ -96,12 +95,12 @@ def test_required_list_str(path: str): @app.get("/required-list-alias") -async def read_required_list_alias(p: Annotated[List[str], Header(alias="p_alias")]): +async def read_required_list_alias(p: Annotated[list[str], Header(alias="p_alias")]): return {"p": p} class HeaderModelRequiredListAlias(BaseModel): - p: List[str] = Field(alias="p_alias") + p: list[str] = Field(alias="p_alias") @app.get("/model-required-list-alias") @@ -219,13 +218,13 @@ def test_required_list_alias_by_alias(path: str): @app.get("/required-list-validation-alias") def read_required_list_validation_alias( - p: Annotated[List[str], Header(validation_alias="p_val_alias")], + p: Annotated[list[str], Header(validation_alias="p_val_alias")], ): return {"p": p} class HeaderModelRequiredListValidationAlias(BaseModel): - p: List[str] = Field(validation_alias="p_val_alias") + p: list[str] = Field(validation_alias="p_val_alias") @app.get("/model-required-list-validation-alias") @@ -328,13 +327,13 @@ def test_required_list_validation_alias_by_validation_alias(path: str): @app.get("/required-list-alias-and-validation-alias") def read_required_list_alias_and_validation_alias( - p: Annotated[List[str], Header(alias="p_alias", validation_alias="p_val_alias")], + p: Annotated[list[str], Header(alias="p_alias", validation_alias="p_val_alias")], ): return {"p": p} class HeaderModelRequiredListAliasAndValidationAlias(BaseModel): - p: List[str] = Field(alias="p_alias", validation_alias="p_val_alias") + p: list[str] = Field(alias="p_alias", validation_alias="p_val_alias") @app.get("/model-required-list-alias-and-validation-alias") diff --git a/tests/test_request_params/test_header/test_optional_list.py b/tests/test_request_params/test_header/test_optional_list.py index e81025c02b..88243f05a9 100644 --- a/tests/test_request_params/test_header/test_optional_list.py +++ b/tests/test_request_params/test_header/test_optional_list.py @@ -1,11 +1,10 @@ -from typing import List, Optional +from typing import Annotated, Optional import pytest from dirty_equals import IsDict from fastapi import FastAPI, Header from fastapi.testclient import TestClient from pydantic import BaseModel, Field -from typing_extensions import Annotated from tests.utils import needs_pydanticv2 @@ -17,13 +16,13 @@ app = FastAPI() @app.get("/optional-list-str") async def read_optional_list_str( - p: Annotated[Optional[List[str]], Header()] = None, + p: Annotated[Optional[list[str]], Header()] = None, ): return {"p": p} class HeaderModelOptionalListStr(BaseModel): - p: Optional[List[str]] = None + p: Optional[list[str]] = None @app.get("/model-optional-list-str") @@ -93,13 +92,13 @@ def test_optional_list_str(path: str): @app.get("/optional-list-alias") async def read_optional_list_alias( - p: Annotated[Optional[List[str]], Header(alias="p_alias")] = None, + p: Annotated[Optional[list[str]], Header(alias="p_alias")] = None, ): return {"p": p} class HeaderModelOptionalListAlias(BaseModel): - p: Optional[List[str]] = Field(None, alias="p_alias") + p: Optional[list[str]] = Field(None, alias="p_alias") @app.get("/model-optional-list-alias") @@ -187,13 +186,13 @@ def test_optional_list_alias_by_alias(path: str): @app.get("/optional-list-validation-alias") def read_optional_list_validation_alias( - p: Annotated[Optional[List[str]], Header(validation_alias="p_val_alias")] = None, + p: Annotated[Optional[list[str]], Header(validation_alias="p_val_alias")] = None, ): return {"p": p} class HeaderModelOptionalListValidationAlias(BaseModel): - p: Optional[List[str]] = Field(None, validation_alias="p_val_alias") + p: Optional[list[str]] = Field(None, validation_alias="p_val_alias") @app.get("/model-optional-list-validation-alias") @@ -273,14 +272,14 @@ def test_optional_list_validation_alias_by_validation_alias(path: str): @app.get("/optional-list-alias-and-validation-alias") def read_optional_list_alias_and_validation_alias( p: Annotated[ - Optional[List[str]], Header(alias="p_alias", validation_alias="p_val_alias") + Optional[list[str]], Header(alias="p_alias", validation_alias="p_val_alias") ] = None, ): return {"p": p} class HeaderModelOptionalListAliasAndValidationAlias(BaseModel): - p: Optional[List[str]] = Field( + p: Optional[list[str]] = Field( None, alias="p_alias", validation_alias="p_val_alias" ) diff --git a/tests/test_request_params/test_header/test_optional_str.py b/tests/test_request_params/test_header/test_optional_str.py index 5ae9f26701..e40b1669ee 100644 --- a/tests/test_request_params/test_header/test_optional_str.py +++ b/tests/test_request_params/test_header/test_optional_str.py @@ -1,11 +1,10 @@ -from typing import Optional +from typing import Annotated, Optional import pytest from dirty_equals import IsDict from fastapi import FastAPI, Header from fastapi.testclient import TestClient from pydantic import BaseModel, Field -from typing_extensions import Annotated from tests.utils import needs_pydanticv2 diff --git a/tests/test_request_params/test_header/test_required_str.py b/tests/test_request_params/test_header/test_required_str.py index d57c66919d..23554d3e4a 100644 --- a/tests/test_request_params/test_header/test_required_str.py +++ b/tests/test_request_params/test_header/test_required_str.py @@ -1,9 +1,10 @@ +from typing import Annotated + import pytest from dirty_equals import AnyThing, IsDict, IsOneOf, IsPartialDict from fastapi import FastAPI, Header from fastapi.testclient import TestClient from pydantic import BaseModel, Field -from typing_extensions import Annotated from tests.utils import needs_pydanticv2 diff --git a/tests/test_request_params/test_path/test_required_str.py b/tests/test_request_params/test_path/test_required_str.py index 6417199674..ecd4eb61cd 100644 --- a/tests/test_request_params/test_path/test_required_str.py +++ b/tests/test_request_params/test_path/test_required_str.py @@ -1,7 +1,8 @@ +from typing import Annotated + import pytest from fastapi import FastAPI, Path from fastapi.testclient import TestClient -from typing_extensions import Annotated from tests.utils import needs_pydanticv2 diff --git a/tests/test_request_params/test_query/test_list.py b/tests/test_request_params/test_query/test_list.py index 71cbca51fb..6a3000fbf6 100644 --- a/tests/test_request_params/test_query/test_list.py +++ b/tests/test_request_params/test_query/test_list.py @@ -1,11 +1,10 @@ -from typing import List +from typing import Annotated import pytest from dirty_equals import IsDict, IsOneOf from fastapi import FastAPI, Query from fastapi.testclient import TestClient from pydantic import BaseModel, Field -from typing_extensions import Annotated from tests.utils import needs_pydanticv2 @@ -16,12 +15,12 @@ app = FastAPI() @app.get("/required-list-str") -async def read_required_list_str(p: Annotated[List[str], Query()]): +async def read_required_list_str(p: Annotated[list[str], Query()]): return {"p": p} class QueryModelRequiredListStr(BaseModel): - p: List[str] + p: list[str] @app.get("/model-required-list-str") @@ -96,12 +95,12 @@ def test_required_list_str(path: str): @app.get("/required-list-alias") -async def read_required_list_alias(p: Annotated[List[str], Query(alias="p_alias")]): +async def read_required_list_alias(p: Annotated[list[str], Query(alias="p_alias")]): return {"p": p} class QueryModelRequiredListAlias(BaseModel): - p: List[str] = Field(alias="p_alias") + p: list[str] = Field(alias="p_alias") @app.get("/model-required-list-alias") @@ -219,13 +218,13 @@ def test_required_list_alias_by_alias(path: str): @app.get("/required-list-validation-alias") def read_required_list_validation_alias( - p: Annotated[List[str], Query(validation_alias="p_val_alias")], + p: Annotated[list[str], Query(validation_alias="p_val_alias")], ): return {"p": p} class QueryModelRequiredListValidationAlias(BaseModel): - p: List[str] = Field(validation_alias="p_val_alias") + p: list[str] = Field(validation_alias="p_val_alias") @app.get("/model-required-list-validation-alias") @@ -326,13 +325,13 @@ def test_required_list_validation_alias_by_validation_alias(path: str): @app.get("/required-list-alias-and-validation-alias") def read_required_list_alias_and_validation_alias( - p: Annotated[List[str], Query(alias="p_alias", validation_alias="p_val_alias")], + p: Annotated[list[str], Query(alias="p_alias", validation_alias="p_val_alias")], ): return {"p": p} class QueryModelRequiredListAliasAndValidationAlias(BaseModel): - p: List[str] = Field(alias="p_alias", validation_alias="p_val_alias") + p: list[str] = Field(alias="p_alias", validation_alias="p_val_alias") @app.get("/model-required-list-alias-and-validation-alias") diff --git a/tests/test_request_params/test_query/test_optional_list.py b/tests/test_request_params/test_query/test_optional_list.py index 5609213364..f4b8ec6a82 100644 --- a/tests/test_request_params/test_query/test_optional_list.py +++ b/tests/test_request_params/test_query/test_optional_list.py @@ -1,11 +1,10 @@ -from typing import List, Optional +from typing import Annotated, Optional import pytest from dirty_equals import IsDict from fastapi import FastAPI, Query from fastapi.testclient import TestClient from pydantic import BaseModel, Field -from typing_extensions import Annotated from tests.utils import needs_pydanticv2 @@ -17,13 +16,13 @@ app = FastAPI() @app.get("/optional-list-str") async def read_optional_list_str( - p: Annotated[Optional[List[str]], Query()] = None, + p: Annotated[Optional[list[str]], Query()] = None, ): return {"p": p} class QueryModelOptionalListStr(BaseModel): - p: Optional[List[str]] = None + p: Optional[list[str]] = None @app.get("/model-optional-list-str") @@ -93,13 +92,13 @@ def test_optional_list_str(path: str): @app.get("/optional-list-alias") async def read_optional_list_alias( - p: Annotated[Optional[List[str]], Query(alias="p_alias")] = None, + p: Annotated[Optional[list[str]], Query(alias="p_alias")] = None, ): return {"p": p} class QueryModelOptionalListAlias(BaseModel): - p: Optional[List[str]] = Field(None, alias="p_alias") + p: Optional[list[str]] = Field(None, alias="p_alias") @app.get("/model-optional-list-alias") @@ -187,13 +186,13 @@ def test_optional_list_alias_by_alias(path: str): @app.get("/optional-list-validation-alias") def read_optional_list_validation_alias( - p: Annotated[Optional[List[str]], Query(validation_alias="p_val_alias")] = None, + p: Annotated[Optional[list[str]], Query(validation_alias="p_val_alias")] = None, ): return {"p": p} class QueryModelOptionalListValidationAlias(BaseModel): - p: Optional[List[str]] = Field(None, validation_alias="p_val_alias") + p: Optional[list[str]] = Field(None, validation_alias="p_val_alias") @app.get("/model-optional-list-validation-alias") @@ -271,14 +270,14 @@ def test_optional_list_validation_alias_by_validation_alias(path: str): @app.get("/optional-list-alias-and-validation-alias") def read_optional_list_alias_and_validation_alias( p: Annotated[ - Optional[List[str]], Query(alias="p_alias", validation_alias="p_val_alias") + Optional[list[str]], Query(alias="p_alias", validation_alias="p_val_alias") ] = None, ): return {"p": p} class QueryModelOptionalListAliasAndValidationAlias(BaseModel): - p: Optional[List[str]] = Field( + p: Optional[list[str]] = Field( None, alias="p_alias", validation_alias="p_val_alias" ) diff --git a/tests/test_request_params/test_query/test_optional_str.py b/tests/test_request_params/test_query/test_optional_str.py index 25e4ea42e6..c7d20e37d1 100644 --- a/tests/test_request_params/test_query/test_optional_str.py +++ b/tests/test_request_params/test_query/test_optional_str.py @@ -1,11 +1,10 @@ -from typing import Optional +from typing import Annotated, Optional import pytest from dirty_equals import IsDict from fastapi import FastAPI, Query from fastapi.testclient import TestClient from pydantic import BaseModel, Field -from typing_extensions import Annotated from tests.utils import needs_pydanticv2 diff --git a/tests/test_request_params/test_query/test_required_str.py b/tests/test_request_params/test_query/test_required_str.py index aa0731e2c6..ce30f3b1f8 100644 --- a/tests/test_request_params/test_query/test_required_str.py +++ b/tests/test_request_params/test_query/test_required_str.py @@ -1,9 +1,10 @@ +from typing import Annotated + import pytest from dirty_equals import IsDict, IsOneOf from fastapi import FastAPI, Query from fastapi.testclient import TestClient from pydantic import BaseModel, Field -from typing_extensions import Annotated from tests.utils import needs_pydanticv2 diff --git a/tests/test_response_by_alias.py b/tests/test_response_by_alias.py index e162cd39b5..5b241c76b6 100644 --- a/tests/test_response_by_alias.py +++ b/tests/test_response_by_alias.py @@ -1,5 +1,3 @@ -from typing import List - from fastapi import FastAPI from fastapi._compat import PYDANTIC_V2 from fastapi.testclient import TestClient @@ -45,7 +43,7 @@ def read_model(): return Model(alias="Foo") -@app.get("/list", response_model=List[Model], response_model_by_alias=False) +@app.get("/list", response_model=list[Model], response_model_by_alias=False) def read_list(): return [{"alias": "Foo"}, {"alias": "Bar"}] @@ -60,7 +58,7 @@ def by_alias_model(): return Model(alias="Foo") -@app.get("/by-alias/list", response_model=List[Model]) +@app.get("/by-alias/list", response_model=list[Model]) def by_alias_list(): return [{"alias": "Foo"}, {"alias": "Bar"}] @@ -75,7 +73,7 @@ def no_alias_model(): return ModelNoAlias(name="Foo") -@app.get("/no-alias/list", response_model=List[ModelNoAlias]) +@app.get("/no-alias/list", response_model=list[ModelNoAlias]) def no_alias_list(): return [{"name": "Foo"}, {"name": "Bar"}] diff --git a/tests/test_response_class_no_mediatype.py b/tests/test_response_class_no_mediatype.py index 706929ac36..4dc164bf92 100644 --- a/tests/test_response_class_no_mediatype.py +++ b/tests/test_response_class_no_mediatype.py @@ -1,5 +1,3 @@ -import typing - from fastapi import FastAPI, Response from fastapi.responses import JSONResponse from fastapi.testclient import TestClient @@ -18,7 +16,7 @@ class Error(BaseModel): class JsonApiError(BaseModel): - errors: typing.List[Error] + errors: list[Error] @app.get( diff --git a/tests/test_response_code_no_body.py b/tests/test_response_code_no_body.py index 3ca8708f12..70456a7462 100644 --- a/tests/test_response_code_no_body.py +++ b/tests/test_response_code_no_body.py @@ -1,5 +1,3 @@ -import typing - from fastapi import FastAPI from fastapi.responses import JSONResponse from fastapi.testclient import TestClient @@ -18,7 +16,7 @@ class Error(BaseModel): class JsonApiError(BaseModel): - errors: typing.List[Error] + errors: list[Error] @app.get( diff --git a/tests/test_response_model_as_return_annotation.py b/tests/test_response_model_as_return_annotation.py index 1745c69b60..44e882a76e 100644 --- a/tests/test_response_model_as_return_annotation.py +++ b/tests/test_response_model_as_return_annotation.py @@ -1,4 +1,4 @@ -from typing import List, Union +from typing import Union import pytest from fastapi import FastAPI @@ -191,7 +191,7 @@ def response_model_filtering_model_annotation_submodel_return_submodel() -> DBUs return DBUser(name="John", surname="Doe", password_hash="secret") -@app.get("/response_model_list_of_model-no_annotation", response_model=List[User]) +@app.get("/response_model_list_of_model-no_annotation", response_model=list[User]) def response_model_list_of_model_no_annotation(): return [ DBUser(name="John", surname="Doe", password_hash="secret"), @@ -200,7 +200,7 @@ def response_model_list_of_model_no_annotation(): @app.get("/no_response_model-annotation_list_of_model") -def no_response_model_annotation_list_of_model() -> List[User]: +def no_response_model_annotation_list_of_model() -> list[User]: return [ DBUser(name="John", surname="Doe", password_hash="secret"), DBUser(name="Jane", surname="Does", password_hash="secret2"), @@ -208,7 +208,7 @@ def no_response_model_annotation_list_of_model() -> List[User]: @app.get("/no_response_model-annotation_forward_ref_list_of_model") -def no_response_model_annotation_forward_ref_list_of_model() -> "List[User]": +def no_response_model_annotation_forward_ref_list_of_model() -> "list[User]": return [ DBUser(name="John", surname="Doe", password_hash="secret"), DBUser(name="Jane", surname="Does", password_hash="secret2"), diff --git a/tests/test_response_model_data_filter.py b/tests/test_response_model_data_filter.py index a3e0f95f04..358697d6df 100644 --- a/tests/test_response_model_data_filter.py +++ b/tests/test_response_model_data_filter.py @@ -1,5 +1,3 @@ -from typing import List - from fastapi import FastAPI from fastapi.testclient import TestClient from pydantic import BaseModel @@ -44,7 +42,7 @@ async def read_pet(pet_id: int): return pet -@app.get("/pets/", response_model=List[PetOut]) +@app.get("/pets/", response_model=list[PetOut]) async def read_pets(): user = UserDB( email="johndoe@example.com", diff --git a/tests/test_response_model_data_filter_no_inheritance.py b/tests/test_response_model_data_filter_no_inheritance.py index 64003a8417..c0c2f3a9dc 100644 --- a/tests/test_response_model_data_filter_no_inheritance.py +++ b/tests/test_response_model_data_filter_no_inheritance.py @@ -1,5 +1,3 @@ -from typing import List - from fastapi import FastAPI from fastapi.testclient import TestClient from pydantic import BaseModel @@ -46,7 +44,7 @@ async def read_pet(pet_id: int): return pet -@app.get("/pets/", response_model=List[PetOut]) +@app.get("/pets/", response_model=list[PetOut]) async def read_pets(): user = UserDB( email="johndoe@example.com", diff --git a/tests/test_response_model_invalid.py b/tests/test_response_model_invalid.py index 88b55a436d..f884b5c74a 100644 --- a/tests/test_response_model_invalid.py +++ b/tests/test_response_model_invalid.py @@ -1,5 +1,3 @@ -from typing import List - import pytest from fastapi import FastAPI from fastapi.exceptions import FastAPIError @@ -22,7 +20,7 @@ def test_invalid_response_model_sub_type_raises(): with pytest.raises(FastAPIError): app = FastAPI() - @app.get("/", response_model=List[NonPydanticModel]) + @app.get("/", response_model=list[NonPydanticModel]) def read_root(): pass # pragma: nocover @@ -40,6 +38,6 @@ def test_invalid_response_model_sub_type_in_responses_raises(): with pytest.raises(FastAPIError): app = FastAPI() - @app.get("/", responses={"500": {"model": List[NonPydanticModel]}}) + @app.get("/", responses={"500": {"model": list[NonPydanticModel]}}) def read_root(): pass # pragma: nocover diff --git a/tests/test_response_model_sub_types.py b/tests/test_response_model_sub_types.py index 660bcee1bb..8036bcb07d 100644 --- a/tests/test_response_model_sub_types.py +++ b/tests/test_response_model_sub_types.py @@ -1,5 +1,3 @@ -from typing import List - from fastapi import FastAPI from fastapi.testclient import TestClient from pydantic import BaseModel @@ -17,7 +15,7 @@ def valid1(): pass -@app.get("/valid2", responses={"500": {"model": List[int]}}) +@app.get("/valid2", responses={"500": {"model": list[int]}}) def valid2(): pass @@ -27,7 +25,7 @@ def valid3(): pass -@app.get("/valid4", responses={"500": {"model": List[Model]}}) +@app.get("/valid4", responses={"500": {"model": list[Model]}}) def valid4(): pass diff --git a/tests/test_router_events.py b/tests/test_router_events.py index dd7ff3314b..9df299cdaa 100644 --- a/tests/test_router_events.py +++ b/tests/test_router_events.py @@ -1,5 +1,6 @@ +from collections.abc import AsyncGenerator from contextlib import asynccontextmanager -from typing import AsyncGenerator, Dict, Union +from typing import Union import pytest from fastapi import APIRouter, FastAPI, Request @@ -28,7 +29,7 @@ def test_router_events(state: State) -> None: app = FastAPI() @app.get("/") - def main() -> Dict[str, str]: + def main() -> dict[str, str]: return {"message": "Hello World"} @app.on_event("startup") @@ -96,7 +97,7 @@ def test_app_lifespan_state(state: State) -> None: app = FastAPI(lifespan=lifespan) @app.get("/") - def main() -> Dict[str, str]: + def main() -> dict[str, str]: return {"message": "Hello World"} assert state.app_startup is False @@ -113,19 +114,19 @@ def test_app_lifespan_state(state: State) -> None: def test_router_nested_lifespan_state(state: State) -> None: @asynccontextmanager - async def lifespan(app: FastAPI) -> AsyncGenerator[Dict[str, bool], None]: + async def lifespan(app: FastAPI) -> AsyncGenerator[dict[str, bool], None]: state.app_startup = True yield {"app": True} state.app_shutdown = True @asynccontextmanager - async def router_lifespan(app: FastAPI) -> AsyncGenerator[Dict[str, bool], None]: + async def router_lifespan(app: FastAPI) -> AsyncGenerator[dict[str, bool], None]: state.router_startup = True yield {"router": True} state.router_shutdown = True @asynccontextmanager - async def subrouter_lifespan(app: FastAPI) -> AsyncGenerator[Dict[str, bool], None]: + async def subrouter_lifespan(app: FastAPI) -> AsyncGenerator[dict[str, bool], None]: state.sub_router_startup = True yield {"sub_router": True} state.sub_router_shutdown = True @@ -139,7 +140,7 @@ def test_router_nested_lifespan_state(state: State) -> None: app.include_router(router) @app.get("/") - def main(request: Request) -> Dict[str, str]: + def main(request: Request) -> dict[str, str]: assert request.state.app assert request.state.router assert request.state.sub_router @@ -175,7 +176,7 @@ def test_router_nested_lifespan_state_overriding_by_parent() -> None: @asynccontextmanager async def lifespan( app: FastAPI, - ) -> AsyncGenerator[Dict[str, Union[str, bool]], None]: + ) -> AsyncGenerator[dict[str, Union[str, bool]], None]: yield { "app_specific": True, "overridden": "app", @@ -184,7 +185,7 @@ def test_router_nested_lifespan_state_overriding_by_parent() -> None: @asynccontextmanager async def router_lifespan( app: FastAPI, - ) -> AsyncGenerator[Dict[str, Union[str, bool]], None]: + ) -> AsyncGenerator[dict[str, Union[str, bool]], None]: yield { "router_specific": True, "overridden": "router", # should override parent @@ -225,7 +226,7 @@ def test_merged_mixed_state_lifespans() -> None: yield @asynccontextmanager - async def router_lifespan(app: FastAPI) -> AsyncGenerator[Dict[str, bool], None]: + async def router_lifespan(app: FastAPI) -> AsyncGenerator[dict[str, bool], None]: yield {"router": True} @asynccontextmanager diff --git a/tests/test_security_oauth2_authorization_code_bearer_scopes_openapi.py b/tests/test_security_oauth2_authorization_code_bearer_scopes_openapi.py index d41f1dc1f0..583007c8b7 100644 --- a/tests/test_security_oauth2_authorization_code_bearer_scopes_openapi.py +++ b/tests/test_security_oauth2_authorization_code_bearer_scopes_openapi.py @@ -1,12 +1,11 @@ # Ref: https://github.com/fastapi/fastapi/issues/14454 -from typing import Optional +from typing import Annotated, Optional from fastapi import APIRouter, Depends, FastAPI, Security from fastapi.security import OAuth2AuthorizationCodeBearer from fastapi.testclient import TestClient from inline_snapshot import snapshot -from typing_extensions import Annotated oauth2_scheme = OAuth2AuthorizationCodeBearer( authorizationUrl="authorize", diff --git a/tests/test_security_oauth2_authorization_code_bearer_scopes_openapi_simple.py b/tests/test_security_oauth2_authorization_code_bearer_scopes_openapi_simple.py index ff866d4fc9..1c21369d33 100644 --- a/tests/test_security_oauth2_authorization_code_bearer_scopes_openapi_simple.py +++ b/tests/test_security_oauth2_authorization_code_bearer_scopes_openapi_simple.py @@ -1,10 +1,11 @@ # Ref: https://github.com/fastapi/fastapi/issues/14454 +from typing import Annotated + from fastapi import Depends, FastAPI, Security from fastapi.security import OAuth2AuthorizationCodeBearer from fastapi.testclient import TestClient from inline_snapshot import snapshot -from typing_extensions import Annotated oauth2_scheme = OAuth2AuthorizationCodeBearer( authorizationUrl="api/oauth/authorize", diff --git a/tests/test_security_scopes.py b/tests/test_security_scopes.py index 248fd2bcc2..fccb026fe2 100644 --- a/tests/test_security_scopes.py +++ b/tests/test_security_scopes.py @@ -1,9 +1,8 @@ -from typing import Dict +from typing import Annotated import pytest from fastapi import Depends, FastAPI, Security from fastapi.testclient import TestClient -from typing_extensions import Annotated @pytest.fixture(name="call_counter") @@ -12,7 +11,7 @@ def call_counter_fixture(): @pytest.fixture(name="app") -def app_fixture(call_counter: Dict[str, int]): +def app_fixture(call_counter: dict[str, int]): def get_db(): call_counter["count"] += 1 return f"db_{call_counter['count']}" @@ -38,7 +37,7 @@ def client_fixture(app: FastAPI): def test_security_scopes_dependency_called_once( - client: TestClient, call_counter: Dict[str, int] + client: TestClient, call_counter: dict[str, int] ): response = client.get("/") diff --git a/tests/test_security_scopes_dont_propagate.py b/tests/test_security_scopes_dont_propagate.py index 2bbcc749d3..c306ed0590 100644 --- a/tests/test_security_scopes_dont_propagate.py +++ b/tests/test_security_scopes_dont_propagate.py @@ -1,11 +1,10 @@ # Ref: https://github.com/tiangolo/fastapi/issues/5623 -from typing import Any, Dict, List +from typing import Annotated, Any from fastapi import FastAPI, Security from fastapi.security import SecurityScopes from fastapi.testclient import TestClient -from typing_extensions import Annotated async def security1(scopes: SecurityScopes): @@ -17,8 +16,8 @@ async def security2(scopes: SecurityScopes): async def dep3( - dep1: Annotated[List[str], Security(security1, scopes=["scope1"])], - dep2: Annotated[List[str], Security(security2, scopes=["scope2"])], + dep1: Annotated[list[str], Security(security1, scopes=["scope1"])], + dep2: Annotated[list[str], Security(security2, scopes=["scope2"])], ): return {"dep1": dep1, "dep2": dep2} @@ -28,7 +27,7 @@ app = FastAPI() @app.get("/scopes") def get_scopes( - dep3: Annotated[Dict[str, Any], Security(dep3, scopes=["scope3"])], + dep3: Annotated[dict[str, Any], Security(dep3, scopes=["scope3"])], ): return dep3 diff --git a/tests/test_security_scopes_sub_dependency.py b/tests/test_security_scopes_sub_dependency.py index 9cc668d8e7..2c64d5f3d5 100644 --- a/tests/test_security_scopes_sub_dependency.py +++ b/tests/test_security_scopes_sub_dependency.py @@ -1,12 +1,12 @@ # Ref: https://github.com/fastapi/fastapi/discussions/6024#discussioncomment-8541913 -from typing import Dict + +from typing import Annotated import pytest from fastapi import Depends, FastAPI, Security from fastapi.security import SecurityScopes from fastapi.testclient import TestClient -from typing_extensions import Annotated @pytest.fixture(name="call_counts") @@ -20,7 +20,7 @@ def call_counts_fixture(): @pytest.fixture(name="app") -def app_fixture(call_counts: Dict[str, int]): +def app_fixture(call_counts: dict[str, int]): def get_db_session(): call_counts["get_db_session"] += 1 return f"db_session_{call_counts['get_db_session']}" @@ -75,7 +75,7 @@ def client_fixture(app: FastAPI): def test_security_scopes_sub_dependency_caching( - client: TestClient, call_counts: Dict[str, int] + client: TestClient, call_counts: dict[str, int] ): response = client.get("/") diff --git a/tests/test_serialize_response.py b/tests/test_serialize_response.py index d823e5e04a..14f88dd931 100644 --- a/tests/test_serialize_response.py +++ b/tests/test_serialize_response.py @@ -1,4 +1,4 @@ -from typing import List, Optional +from typing import Optional from fastapi import FastAPI from fastapi.testclient import TestClient @@ -10,7 +10,7 @@ app = FastAPI() class Item(BaseModel): name: str price: Optional[float] = None - owner_ids: Optional[List[int]] = None + owner_ids: Optional[list[int]] = None @app.get("/items/valid", response_model=Item) @@ -23,7 +23,7 @@ def get_coerce(): return {"name": "coerce", "price": "1.0"} -@app.get("/items/validlist", response_model=List[Item]) +@app.get("/items/validlist", response_model=list[Item]) def get_validlist(): return [ {"name": "foo"}, diff --git a/tests/test_serialize_response_dataclass.py b/tests/test_serialize_response_dataclass.py index 1e3bf3b28b..ee695368b8 100644 --- a/tests/test_serialize_response_dataclass.py +++ b/tests/test_serialize_response_dataclass.py @@ -1,6 +1,6 @@ from dataclasses import dataclass from datetime import datetime -from typing import List, Optional +from typing import Optional from fastapi import FastAPI from fastapi.testclient import TestClient @@ -13,7 +13,7 @@ class Item: name: str date: datetime price: Optional[float] = None - owner_ids: Optional[List[int]] = None + owner_ids: Optional[list[int]] = None @app.get("/items/valid", response_model=Item) @@ -33,7 +33,7 @@ def get_coerce(): return {"name": "coerce", "date": datetime(2021, 7, 26).isoformat(), "price": "1.0"} -@app.get("/items/validlist", response_model=List[Item]) +@app.get("/items/validlist", response_model=list[Item]) def get_validlist(): return [ {"name": "foo", "date": datetime(2021, 7, 26)}, @@ -47,7 +47,7 @@ def get_validlist(): ] -@app.get("/items/objectlist", response_model=List[Item]) +@app.get("/items/objectlist", response_model=list[Item]) def get_objectlist(): return [ Item(name="foo", date=datetime(2021, 7, 26)), diff --git a/tests/test_serialize_response_model.py b/tests/test_serialize_response_model.py index 3bb46b2e9b..79c90c9c29 100644 --- a/tests/test_serialize_response_model.py +++ b/tests/test_serialize_response_model.py @@ -1,4 +1,4 @@ -from typing import Dict, List, Optional +from typing import Optional from fastapi import FastAPI from pydantic import BaseModel, Field @@ -10,7 +10,7 @@ app = FastAPI() class Item(BaseModel): name: str = Field(alias="aliased_name") price: Optional[float] = None - owner_ids: Optional[List[int]] = None + owner_ids: Optional[list[int]] = None @app.get("/items/valid", response_model=Item) @@ -23,7 +23,7 @@ def get_coerce(): return Item(aliased_name="coerce", price="1.0") -@app.get("/items/validlist", response_model=List[Item]) +@app.get("/items/validlist", response_model=list[Item]) def get_validlist(): return [ Item(aliased_name="foo"), @@ -32,7 +32,7 @@ def get_validlist(): ] -@app.get("/items/validdict", response_model=Dict[str, Item]) +@app.get("/items/validdict", response_model=dict[str, Item]) def get_validdict(): return { "k1": Item(aliased_name="foo"), @@ -59,7 +59,7 @@ def get_coerce_exclude_unset(): @app.get( "/items/validlist-exclude-unset", - response_model=List[Item], + response_model=list[Item], response_model_exclude_unset=True, ) def get_validlist_exclude_unset(): @@ -72,7 +72,7 @@ def get_validlist_exclude_unset(): @app.get( "/items/validdict-exclude-unset", - response_model=Dict[str, Item], + response_model=dict[str, Item], response_model_exclude_unset=True, ) def get_validdict_exclude_unset(): diff --git a/tests/test_stringified_annotation_dependency.py b/tests/test_stringified_annotation_dependency.py index 89bb884b5c..ce88074957 100644 --- a/tests/test_stringified_annotation_dependency.py +++ b/tests/test_stringified_annotation_dependency.py @@ -1,12 +1,11 @@ from __future__ import annotations -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, Annotated import pytest from fastapi import Depends, FastAPI from fastapi.testclient import TestClient from inline_snapshot import snapshot -from typing_extensions import Annotated if TYPE_CHECKING: # pragma: no cover from collections.abc import AsyncGenerator diff --git a/tests/test_stringified_annotations_simple.py b/tests/test_stringified_annotations_simple.py index 9bd6d09d63..6e037fb21f 100644 --- a/tests/test_stringified_annotations_simple.py +++ b/tests/test_stringified_annotations_simple.py @@ -1,8 +1,9 @@ from __future__ import annotations +from typing import Annotated + from fastapi import Depends, FastAPI, Request from fastapi.testclient import TestClient -from typing_extensions import Annotated from .utils import needs_py310 diff --git a/tests/test_tuples.py b/tests/test_tuples.py index ca33d2580c..fbc69a6145 100644 --- a/tests/test_tuples.py +++ b/tests/test_tuples.py @@ -1,5 +1,3 @@ -from typing import List, Tuple - from dirty_equals import IsDict from fastapi import FastAPI, Form from fastapi.testclient import TestClient @@ -9,7 +7,7 @@ app = FastAPI() class ItemGroup(BaseModel): - items: List[Tuple[str, str]] + items: list[tuple[str, str]] class Coordinate(BaseModel): @@ -23,12 +21,12 @@ def post_model_with_tuple(item_group: ItemGroup): @app.post("/tuple-of-models/") -def post_tuple_of_models(square: Tuple[Coordinate, Coordinate]): +def post_tuple_of_models(square: tuple[Coordinate, Coordinate]): return square @app.post("/tuple-form/") -def hello(values: Tuple[int, int] = Form()): +def hello(values: tuple[int, int] = Form()): return values diff --git a/tests/test_tutorial/test_additional_responses/test_tutorial001.py b/tests/test_tutorial/test_additional_responses/test_tutorial001.py index 3afeaff840..1a18db75ce 100644 --- a/tests/test_tutorial/test_additional_responses/test_tutorial001.py +++ b/tests/test_tutorial/test_additional_responses/test_tutorial001.py @@ -1,6 +1,6 @@ from fastapi.testclient import TestClient -from docs_src.additional_responses.tutorial001 import app +from docs_src.additional_responses.tutorial001_py39 import app client = TestClient(app) diff --git a/tests/test_tutorial/test_additional_responses/test_tutorial002.py b/tests/test_tutorial/test_additional_responses/test_tutorial002.py index 91d6ff101f..bbcad8f294 100644 --- a/tests/test_tutorial/test_additional_responses/test_tutorial002.py +++ b/tests/test_tutorial/test_additional_responses/test_tutorial002.py @@ -12,7 +12,7 @@ from tests.utils import needs_py310 @pytest.fixture( name="client", params=[ - pytest.param("tutorial002"), + pytest.param("tutorial002_py39"), pytest.param("tutorial002_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_additional_responses/test_tutorial003.py b/tests/test_tutorial/test_additional_responses/test_tutorial003.py index bd34d2938c..90dc4e371e 100644 --- a/tests/test_tutorial/test_additional_responses/test_tutorial003.py +++ b/tests/test_tutorial/test_additional_responses/test_tutorial003.py @@ -1,6 +1,6 @@ from fastapi.testclient import TestClient -from docs_src.additional_responses.tutorial003 import app +from docs_src.additional_responses.tutorial003_py39 import app client = TestClient(app) diff --git a/tests/test_tutorial/test_additional_responses/test_tutorial004.py b/tests/test_tutorial/test_additional_responses/test_tutorial004.py index 2d9491467e..cbd4fff7d6 100644 --- a/tests/test_tutorial/test_additional_responses/test_tutorial004.py +++ b/tests/test_tutorial/test_additional_responses/test_tutorial004.py @@ -12,7 +12,7 @@ from tests.utils import needs_py310 @pytest.fixture( name="client", params=[ - pytest.param("tutorial004"), + pytest.param("tutorial004_py39"), pytest.param("tutorial004_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_additional_status_codes/test_tutorial001.py b/tests/test_tutorial/test_additional_status_codes/test_tutorial001.py index b304f70153..bced1f6dfe 100644 --- a/tests/test_tutorial/test_additional_status_codes/test_tutorial001.py +++ b/tests/test_tutorial/test_additional_status_codes/test_tutorial001.py @@ -3,16 +3,15 @@ import importlib import pytest from fastapi.testclient import TestClient -from ...utils import needs_py39, needs_py310 +from ...utils import needs_py310 @pytest.fixture( name="client", params=[ - "tutorial001", + "tutorial001_py39", pytest.param("tutorial001_py310", marks=needs_py310), - "tutorial001_an", - pytest.param("tutorial001_an_py39", marks=needs_py39), + "tutorial001_an_py39", pytest.param("tutorial001_an_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_advanced_middleware/test_tutorial001.py b/tests/test_tutorial/test_advanced_middleware/test_tutorial001.py index 157fa5caf1..f17391956e 100644 --- a/tests/test_tutorial/test_advanced_middleware/test_tutorial001.py +++ b/tests/test_tutorial/test_advanced_middleware/test_tutorial001.py @@ -1,6 +1,6 @@ from fastapi.testclient import TestClient -from docs_src.advanced_middleware.tutorial001 import app +from docs_src.advanced_middleware.tutorial001_py39 import app def test_middleware(): diff --git a/tests/test_tutorial/test_advanced_middleware/test_tutorial002.py b/tests/test_tutorial/test_advanced_middleware/test_tutorial002.py index 79be52f4db..bae915406e 100644 --- a/tests/test_tutorial/test_advanced_middleware/test_tutorial002.py +++ b/tests/test_tutorial/test_advanced_middleware/test_tutorial002.py @@ -1,6 +1,6 @@ from fastapi.testclient import TestClient -from docs_src.advanced_middleware.tutorial002 import app +from docs_src.advanced_middleware.tutorial002_py39 import app def test_middleware(): diff --git a/tests/test_tutorial/test_advanced_middleware/test_tutorial003.py b/tests/test_tutorial/test_advanced_middleware/test_tutorial003.py index 04a922ff7b..66697997c8 100644 --- a/tests/test_tutorial/test_advanced_middleware/test_tutorial003.py +++ b/tests/test_tutorial/test_advanced_middleware/test_tutorial003.py @@ -1,7 +1,7 @@ from fastapi.responses import PlainTextResponse from fastapi.testclient import TestClient -from docs_src.advanced_middleware.tutorial003 import app +from docs_src.advanced_middleware.tutorial003_py39 import app @app.get("/large") diff --git a/tests/test_tutorial/test_async_tests/test_main.py b/tests/test_tutorial/test_async_tests/test_main_a.py similarity index 58% rename from tests/test_tutorial/test_async_tests/test_main.py rename to tests/test_tutorial/test_async_tests/test_main_a.py index 1f5d7186cc..f29acaa9a0 100644 --- a/tests/test_tutorial/test_async_tests/test_main.py +++ b/tests/test_tutorial/test_async_tests/test_main_a.py @@ -1,6 +1,6 @@ import pytest -from docs_src.async_tests.test_main import test_root +from docs_src.async_tests.app_a_py39.test_main import test_root @pytest.mark.anyio diff --git a/tests/test_tutorial/test_authentication_error_status_code/test_tutorial001.py b/tests/test_tutorial/test_authentication_error_status_code/test_tutorial001.py index bbd7bff30f..6f58116313 100644 --- a/tests/test_tutorial/test_authentication_error_status_code/test_tutorial001.py +++ b/tests/test_tutorial/test_authentication_error_status_code/test_tutorial001.py @@ -4,14 +4,11 @@ import pytest from fastapi.testclient import TestClient from inline_snapshot import snapshot -from ...utils import needs_py39 - @pytest.fixture( name="client", params=[ - "tutorial001_an", - pytest.param("tutorial001_an_py39", marks=needs_py39), + "tutorial001_an_py39", ], ) def get_client(request: pytest.FixtureRequest): diff --git a/tests/test_tutorial/test_background_tasks/test_tutorial001.py b/tests/test_tutorial/test_background_tasks/test_tutorial001.py index 0602cd8aa4..c0ad27a6f5 100644 --- a/tests/test_tutorial/test_background_tasks/test_tutorial001.py +++ b/tests/test_tutorial/test_background_tasks/test_tutorial001.py @@ -3,7 +3,7 @@ from pathlib import Path from fastapi.testclient import TestClient -from docs_src.background_tasks.tutorial001 import app +from docs_src.background_tasks.tutorial001_py39 import app client = TestClient(app) diff --git a/tests/test_tutorial/test_background_tasks/test_tutorial002.py b/tests/test_tutorial/test_background_tasks/test_tutorial002.py index d5ef51ee2b..288a1c244e 100644 --- a/tests/test_tutorial/test_background_tasks/test_tutorial002.py +++ b/tests/test_tutorial/test_background_tasks/test_tutorial002.py @@ -5,16 +5,15 @@ from pathlib import Path import pytest from fastapi.testclient import TestClient -from ...utils import needs_py39, needs_py310 +from ...utils import needs_py310 @pytest.fixture( name="client", params=[ - "tutorial002", + "tutorial002_py39", pytest.param("tutorial002_py310", marks=needs_py310), - "tutorial002_an", - pytest.param("tutorial002_an_py39", marks=needs_py39), + "tutorial002_an_py39", pytest.param("tutorial002_an_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_behind_a_proxy/test_tutorial001.py b/tests/test_tutorial/test_behind_a_proxy/test_tutorial001.py index a070f850f7..00574b5b0f 100644 --- a/tests/test_tutorial/test_behind_a_proxy/test_tutorial001.py +++ b/tests/test_tutorial/test_behind_a_proxy/test_tutorial001.py @@ -1,6 +1,6 @@ from fastapi.testclient import TestClient -from docs_src.behind_a_proxy.tutorial001 import app +from docs_src.behind_a_proxy.tutorial001_py39 import app client = TestClient(app, root_path="/api/v1") diff --git a/tests/test_tutorial/test_behind_a_proxy/test_tutorial001_01.py b/tests/test_tutorial/test_behind_a_proxy/test_tutorial001_01.py index f13046e018..da4acb28cc 100644 --- a/tests/test_tutorial/test_behind_a_proxy/test_tutorial001_01.py +++ b/tests/test_tutorial/test_behind_a_proxy/test_tutorial001_01.py @@ -1,6 +1,6 @@ from fastapi.testclient import TestClient -from docs_src.behind_a_proxy.tutorial001_01 import app +from docs_src.behind_a_proxy.tutorial001_01_py39 import app client = TestClient( app, diff --git a/tests/test_tutorial/test_behind_a_proxy/test_tutorial002.py b/tests/test_tutorial/test_behind_a_proxy/test_tutorial002.py index ce791e2157..1a49c0dfeb 100644 --- a/tests/test_tutorial/test_behind_a_proxy/test_tutorial002.py +++ b/tests/test_tutorial/test_behind_a_proxy/test_tutorial002.py @@ -1,6 +1,6 @@ from fastapi.testclient import TestClient -from docs_src.behind_a_proxy.tutorial002 import app +from docs_src.behind_a_proxy.tutorial002_py39 import app client = TestClient(app) diff --git a/tests/test_tutorial/test_behind_a_proxy/test_tutorial003.py b/tests/test_tutorial/test_behind_a_proxy/test_tutorial003.py index ec17b41790..2d1d1b03c8 100644 --- a/tests/test_tutorial/test_behind_a_proxy/test_tutorial003.py +++ b/tests/test_tutorial/test_behind_a_proxy/test_tutorial003.py @@ -1,7 +1,7 @@ from dirty_equals import IsOneOf from fastapi.testclient import TestClient -from docs_src.behind_a_proxy.tutorial003 import app +from docs_src.behind_a_proxy.tutorial003_py39 import app client = TestClient(app) diff --git a/tests/test_tutorial/test_behind_a_proxy/test_tutorial004.py b/tests/test_tutorial/test_behind_a_proxy/test_tutorial004.py index 2f8eb46995..e8a03e8112 100644 --- a/tests/test_tutorial/test_behind_a_proxy/test_tutorial004.py +++ b/tests/test_tutorial/test_behind_a_proxy/test_tutorial004.py @@ -1,7 +1,7 @@ from dirty_equals import IsOneOf from fastapi.testclient import TestClient -from docs_src.behind_a_proxy.tutorial004 import app +from docs_src.behind_a_proxy.tutorial004_py39 import app client = TestClient(app) diff --git a/tests/test_tutorial/test_bigger_applications/test_main.py b/tests/test_tutorial/test_bigger_applications/test_main.py index fe40fad7d0..7493a9e661 100644 --- a/tests/test_tutorial/test_bigger_applications/test_main.py +++ b/tests/test_tutorial/test_bigger_applications/test_main.py @@ -4,15 +4,12 @@ import pytest from dirty_equals import IsDict from fastapi.testclient import TestClient -from ...utils import needs_py39 - @pytest.fixture( name="client", params=[ - "app_an.main", - pytest.param("app_an_py39.main", marks=needs_py39), - "app.main", + "app_py39.main", + "app_an_py39.main", ], ) def get_client(request: pytest.FixtureRequest): diff --git a/tests/test_tutorial/test_body/test_tutorial001.py b/tests/test_tutorial/test_body/test_tutorial001.py index f8b5aee8d2..6aa9f2593e 100644 --- a/tests/test_tutorial/test_body/test_tutorial001.py +++ b/tests/test_tutorial/test_body/test_tutorial001.py @@ -11,7 +11,7 @@ from ...utils import needs_py310 @pytest.fixture( name="client", params=[ - "tutorial001", + "tutorial001_py39", pytest.param("tutorial001_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_body_fields/test_tutorial001.py b/tests/test_tutorial/test_body_fields/test_tutorial001.py index fb68f28689..d54ec7191a 100644 --- a/tests/test_tutorial/test_body_fields/test_tutorial001.py +++ b/tests/test_tutorial/test_body_fields/test_tutorial001.py @@ -4,16 +4,15 @@ import pytest from dirty_equals import IsDict from fastapi.testclient import TestClient -from ...utils import needs_py39, needs_py310 +from ...utils import needs_py310 @pytest.fixture( name="client", params=[ - "tutorial001", + "tutorial001_py39", pytest.param("tutorial001_py310", marks=needs_py310), - "tutorial001_an", - pytest.param("tutorial001_an_py39", marks=needs_py39), + "tutorial001_an_py39", pytest.param("tutorial001_an_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_body_multiple_params/test_tutorial001.py b/tests/test_tutorial/test_body_multiple_params/test_tutorial001.py index 1424055952..2035cf9448 100644 --- a/tests/test_tutorial/test_body_multiple_params/test_tutorial001.py +++ b/tests/test_tutorial/test_body_multiple_params/test_tutorial001.py @@ -4,16 +4,15 @@ import pytest from dirty_equals import IsDict from fastapi.testclient import TestClient -from ...utils import needs_py39, needs_py310 +from ...utils import needs_py310 @pytest.fixture( name="client", params=[ - "tutorial001", + "tutorial001_py39", pytest.param("tutorial001_py310", marks=needs_py310), - "tutorial001_an", - pytest.param("tutorial001_an_py39", marks=needs_py39), + "tutorial001_an_py39", pytest.param("tutorial001_an_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_body_multiple_params/test_tutorial003.py b/tests/test_tutorial/test_body_multiple_params/test_tutorial003.py index d18ceae486..d3e6401af2 100644 --- a/tests/test_tutorial/test_body_multiple_params/test_tutorial003.py +++ b/tests/test_tutorial/test_body_multiple_params/test_tutorial003.py @@ -4,16 +4,15 @@ import pytest from dirty_equals import IsDict from fastapi.testclient import TestClient -from ...utils import needs_py39, needs_py310 +from ...utils import needs_py310 @pytest.fixture( name="client", params=[ - "tutorial003", + "tutorial003_py39", pytest.param("tutorial003_py310", marks=needs_py310), - "tutorial003_an", - pytest.param("tutorial003_an_py39", marks=needs_py39), + "tutorial003_an_py39", pytest.param("tutorial003_an_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_body_nested_models/test_tutorial009.py b/tests/test_tutorial/test_body_nested_models/test_tutorial009.py index 38ba3c8875..db9f04546e 100644 --- a/tests/test_tutorial/test_body_nested_models/test_tutorial009.py +++ b/tests/test_tutorial/test_body_nested_models/test_tutorial009.py @@ -4,14 +4,11 @@ import pytest from dirty_equals import IsDict from fastapi.testclient import TestClient -from ...utils import needs_py39 - @pytest.fixture( name="client", params=[ - "tutorial009", - pytest.param("tutorial009_py39", marks=needs_py39), + "tutorial009_py39", ], ) def get_client(request: pytest.FixtureRequest): diff --git a/tests/test_tutorial/test_body_updates/test_tutorial001.py b/tests/test_tutorial/test_body_updates/test_tutorial001.py index f874dc9bd6..8bbc4d6992 100644 --- a/tests/test_tutorial/test_body_updates/test_tutorial001.py +++ b/tests/test_tutorial/test_body_updates/test_tutorial001.py @@ -3,15 +3,14 @@ import importlib import pytest from fastapi.testclient import TestClient -from ...utils import needs_py39, needs_py310, needs_pydanticv1, needs_pydanticv2 +from ...utils import needs_py310, needs_pydanticv1, needs_pydanticv2 @pytest.fixture( name="client", params=[ - "tutorial001", + "tutorial001_py39", pytest.param("tutorial001_py310", marks=needs_py310), - pytest.param("tutorial001_py39", marks=needs_py39), ], ) def get_client(request: pytest.FixtureRequest): diff --git a/tests/test_tutorial/test_conditional_openapi/test_tutorial001.py b/tests/test_tutorial/test_conditional_openapi/test_tutorial001.py index b098f259c2..a425e893d8 100644 --- a/tests/test_tutorial/test_conditional_openapi/test_tutorial001.py +++ b/tests/test_tutorial/test_conditional_openapi/test_tutorial001.py @@ -6,11 +6,11 @@ from ...utils import needs_pydanticv2 def get_client() -> TestClient: - from docs_src.conditional_openapi import tutorial001 + from docs_src.conditional_openapi import tutorial001_py39 - importlib.reload(tutorial001) + importlib.reload(tutorial001_py39) - client = TestClient(tutorial001.app) + client = TestClient(tutorial001_py39.app) return client diff --git a/tests/test_tutorial/test_configure_swagger_ui/test_tutorial001.py b/tests/test_tutorial/test_configure_swagger_ui/test_tutorial001.py index a04dba2197..1fa9419a76 100644 --- a/tests/test_tutorial/test_configure_swagger_ui/test_tutorial001.py +++ b/tests/test_tutorial/test_configure_swagger_ui/test_tutorial001.py @@ -1,6 +1,6 @@ from fastapi.testclient import TestClient -from docs_src.configure_swagger_ui.tutorial001 import app +from docs_src.configure_swagger_ui.tutorial001_py39 import app client = TestClient(app) diff --git a/tests/test_tutorial/test_configure_swagger_ui/test_tutorial002.py b/tests/test_tutorial/test_configure_swagger_ui/test_tutorial002.py index ea56b6f21c..c218cc858c 100644 --- a/tests/test_tutorial/test_configure_swagger_ui/test_tutorial002.py +++ b/tests/test_tutorial/test_configure_swagger_ui/test_tutorial002.py @@ -1,6 +1,6 @@ from fastapi.testclient import TestClient -from docs_src.configure_swagger_ui.tutorial002 import app +from docs_src.configure_swagger_ui.tutorial002_py39 import app client = TestClient(app) diff --git a/tests/test_tutorial/test_configure_swagger_ui/test_tutorial003.py b/tests/test_tutorial/test_configure_swagger_ui/test_tutorial003.py index 926bbb14f0..8b73685499 100644 --- a/tests/test_tutorial/test_configure_swagger_ui/test_tutorial003.py +++ b/tests/test_tutorial/test_configure_swagger_ui/test_tutorial003.py @@ -1,6 +1,6 @@ from fastapi.testclient import TestClient -from docs_src.configure_swagger_ui.tutorial003 import app +from docs_src.configure_swagger_ui.tutorial003_py39 import app client = TestClient(app) diff --git a/tests/test_tutorial/test_cookie_param_models/test_tutorial001.py b/tests/test_tutorial/test_cookie_param_models/test_tutorial001.py index 60643185a4..265dee944e 100644 --- a/tests/test_tutorial/test_cookie_param_models/test_tutorial001.py +++ b/tests/test_tutorial/test_cookie_param_models/test_tutorial001.py @@ -5,16 +5,15 @@ from dirty_equals import IsDict from fastapi.testclient import TestClient from inline_snapshot import snapshot -from tests.utils import needs_py39, needs_py310 +from tests.utils import needs_py310 @pytest.fixture( name="client", params=[ - "tutorial001", + "tutorial001_py39", pytest.param("tutorial001_py310", marks=needs_py310), - "tutorial001_an", - pytest.param("tutorial001_an_py39", marks=needs_py39), + "tutorial001_an_py39", pytest.param("tutorial001_an_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_cookie_param_models/test_tutorial002.py b/tests/test_tutorial/test_cookie_param_models/test_tutorial002.py index cef6f66309..4a826a5374 100644 --- a/tests/test_tutorial/test_cookie_param_models/test_tutorial002.py +++ b/tests/test_tutorial/test_cookie_param_models/test_tutorial002.py @@ -6,7 +6,6 @@ from fastapi.testclient import TestClient from inline_snapshot import snapshot from tests.utils import ( - needs_py39, needs_py310, needs_pydanticv1, needs_pydanticv2, @@ -17,15 +16,13 @@ from tests.utils import ( @pytest.fixture( name="client", params=[ - pytest.param("tutorial002", marks=needs_pydanticv2), + pytest.param("tutorial002_py39", marks=needs_pydanticv2), pytest.param("tutorial002_py310", marks=[needs_py310, needs_pydanticv2]), - pytest.param("tutorial002_an", marks=needs_pydanticv2), - pytest.param("tutorial002_an_py39", marks=[needs_py39, needs_pydanticv2]), + pytest.param("tutorial002_an_py39", marks=needs_pydanticv2), pytest.param("tutorial002_an_py310", marks=[needs_py310, needs_pydanticv2]), - pytest.param("tutorial002_pv1", marks=[needs_pydanticv1, needs_pydanticv1]), + pytest.param("tutorial002_pv1_py39", marks=needs_pydanticv1), pytest.param("tutorial002_pv1_py310", marks=[needs_py310, needs_pydanticv1]), - pytest.param("tutorial002_pv1_an", marks=[needs_pydanticv1]), - pytest.param("tutorial002_pv1_an_py39", marks=[needs_py39, needs_pydanticv1]), + pytest.param("tutorial002_pv1_an_py39", marks=needs_pydanticv1), pytest.param("tutorial002_pv1_an_py310", marks=[needs_py310, needs_pydanticv1]), ], ) diff --git a/tests/test_tutorial/test_cookie_params/test_tutorial001.py b/tests/test_tutorial/test_cookie_params/test_tutorial001.py index 90e8dfd37c..a65249d657 100644 --- a/tests/test_tutorial/test_cookie_params/test_tutorial001.py +++ b/tests/test_tutorial/test_cookie_params/test_tutorial001.py @@ -5,16 +5,15 @@ import pytest from dirty_equals import IsDict from fastapi.testclient import TestClient -from ...utils import needs_py39, needs_py310 +from ...utils import needs_py310 @pytest.fixture( name="mod", params=[ - "tutorial001", + "tutorial001_py39", pytest.param("tutorial001_py310", marks=needs_py310), - "tutorial001_an", - pytest.param("tutorial001_an_py39", marks=needs_py39), + "tutorial001_an_py39", pytest.param("tutorial001_an_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_cors/test_tutorial001.py b/tests/test_tutorial/test_cors/test_tutorial001.py index f62c9df4f9..6a733693ae 100644 --- a/tests/test_tutorial/test_cors/test_tutorial001.py +++ b/tests/test_tutorial/test_cors/test_tutorial001.py @@ -1,6 +1,6 @@ from fastapi.testclient import TestClient -from docs_src.cors.tutorial001 import app +from docs_src.cors.tutorial001_py39 import app def test_cors(): diff --git a/tests/test_tutorial/test_custom_docs_ui/test_tutorial001.py b/tests/test_tutorial/test_custom_docs_ui/test_tutorial001.py index cb8e8c2248..1816e5d975 100644 --- a/tests/test_tutorial/test_custom_docs_ui/test_tutorial001.py +++ b/tests/test_tutorial/test_custom_docs_ui/test_tutorial001.py @@ -10,7 +10,7 @@ def client(): static_dir: Path = Path(os.getcwd()) / "static" print(static_dir) static_dir.mkdir(exist_ok=True) - from docs_src.custom_docs_ui.tutorial001 import app + from docs_src.custom_docs_ui.tutorial001_py39 import app with TestClient(app) as client: yield client diff --git a/tests/test_tutorial/test_custom_docs_ui/test_tutorial002.py b/tests/test_tutorial/test_custom_docs_ui/test_tutorial002.py index 712618807c..e8b7eb7aa3 100644 --- a/tests/test_tutorial/test_custom_docs_ui/test_tutorial002.py +++ b/tests/test_tutorial/test_custom_docs_ui/test_tutorial002.py @@ -10,7 +10,7 @@ def client(): static_dir: Path = Path(os.getcwd()) / "static" print(static_dir) static_dir.mkdir(exist_ok=True) - from docs_src.custom_docs_ui.tutorial002 import app + from docs_src.custom_docs_ui.tutorial002_py39 import app with TestClient(app) as client: yield client diff --git a/tests/test_tutorial/test_custom_request_and_route/test_tutorial001.py b/tests/test_tutorial/test_custom_request_and_route/test_tutorial001.py index f9fd0d1af8..b4ea537846 100644 --- a/tests/test_tutorial/test_custom_request_and_route/test_tutorial001.py +++ b/tests/test_tutorial/test_custom_request_and_route/test_tutorial001.py @@ -6,17 +6,15 @@ import pytest from fastapi import Request from fastapi.testclient import TestClient -from tests.utils import needs_py39, needs_py310 +from tests.utils import needs_py310 @pytest.fixture( name="client", params=[ - pytest.param("tutorial001"), - pytest.param("tutorial001_py39", marks=needs_py39), + pytest.param("tutorial001_py39"), pytest.param("tutorial001_py310", marks=needs_py310), - pytest.param("tutorial001_an"), - pytest.param("tutorial001_an_py39", marks=needs_py39), + pytest.param("tutorial001_an_py39"), pytest.param("tutorial001_an_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_custom_request_and_route/test_tutorial002.py b/tests/test_tutorial/test_custom_request_and_route/test_tutorial002.py index c35752ed13..643011637e 100644 --- a/tests/test_tutorial/test_custom_request_and_route/test_tutorial002.py +++ b/tests/test_tutorial/test_custom_request_and_route/test_tutorial002.py @@ -4,17 +4,15 @@ import pytest from dirty_equals import IsDict, IsOneOf from fastapi.testclient import TestClient -from tests.utils import needs_py39, needs_py310 +from tests.utils import needs_py310 @pytest.fixture( name="client", params=[ - pytest.param("tutorial002"), - pytest.param("tutorial002_py39", marks=needs_py39), + pytest.param("tutorial002_py39"), pytest.param("tutorial002_py310", marks=needs_py310), - pytest.param("tutorial002_an"), - pytest.param("tutorial002_an_py39", marks=needs_py39), + pytest.param("tutorial002_an_py39"), pytest.param("tutorial002_an_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_custom_request_and_route/test_tutorial003.py b/tests/test_tutorial/test_custom_request_and_route/test_tutorial003.py index 9e895b2daf..6cad7bd3f0 100644 --- a/tests/test_tutorial/test_custom_request_and_route/test_tutorial003.py +++ b/tests/test_tutorial/test_custom_request_and_route/test_tutorial003.py @@ -9,7 +9,7 @@ from tests.utils import needs_py310 @pytest.fixture( name="client", params=[ - pytest.param("tutorial003"), + pytest.param("tutorial003_py39"), pytest.param("tutorial003_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_custom_response/test_tutorial001.py b/tests/test_tutorial/test_custom_response/test_tutorial001.py index fc83624673..c81e991ebf 100644 --- a/tests/test_tutorial/test_custom_response/test_tutorial001.py +++ b/tests/test_tutorial/test_custom_response/test_tutorial001.py @@ -1,6 +1,6 @@ from fastapi.testclient import TestClient -from docs_src.custom_response.tutorial001 import app +from docs_src.custom_response.tutorial001_py39 import app client = TestClient(app) diff --git a/tests/test_tutorial/test_custom_response/test_tutorial001b.py b/tests/test_tutorial/test_custom_response/test_tutorial001b.py index 91e5c501e3..3337f47d5f 100644 --- a/tests/test_tutorial/test_custom_response/test_tutorial001b.py +++ b/tests/test_tutorial/test_custom_response/test_tutorial001b.py @@ -1,6 +1,6 @@ from fastapi.testclient import TestClient -from docs_src.custom_response.tutorial001b import app +from docs_src.custom_response.tutorial001b_py39 import app client = TestClient(app) diff --git a/tests/test_tutorial/test_custom_response/test_tutorial004.py b/tests/test_tutorial/test_custom_response/test_tutorial004.py index de60574f5e..0e7d69791b 100644 --- a/tests/test_tutorial/test_custom_response/test_tutorial004.py +++ b/tests/test_tutorial/test_custom_response/test_tutorial004.py @@ -1,6 +1,6 @@ from fastapi.testclient import TestClient -from docs_src.custom_response.tutorial004 import app +from docs_src.custom_response.tutorial004_py39 import app client = TestClient(app) diff --git a/tests/test_tutorial/test_custom_response/test_tutorial005.py b/tests/test_tutorial/test_custom_response/test_tutorial005.py index 889bf3e929..fea105c28e 100644 --- a/tests/test_tutorial/test_custom_response/test_tutorial005.py +++ b/tests/test_tutorial/test_custom_response/test_tutorial005.py @@ -1,6 +1,6 @@ from fastapi.testclient import TestClient -from docs_src.custom_response.tutorial005 import app +from docs_src.custom_response.tutorial005_py39 import app client = TestClient(app) diff --git a/tests/test_tutorial/test_custom_response/test_tutorial006.py b/tests/test_tutorial/test_custom_response/test_tutorial006.py index 2d0a2cd3f6..e9e6ca1086 100644 --- a/tests/test_tutorial/test_custom_response/test_tutorial006.py +++ b/tests/test_tutorial/test_custom_response/test_tutorial006.py @@ -1,6 +1,6 @@ from fastapi.testclient import TestClient -from docs_src.custom_response.tutorial006 import app +from docs_src.custom_response.tutorial006_py39 import app client = TestClient(app) diff --git a/tests/test_tutorial/test_custom_response/test_tutorial006b.py b/tests/test_tutorial/test_custom_response/test_tutorial006b.py index 1739fd4570..7ca727d2cd 100644 --- a/tests/test_tutorial/test_custom_response/test_tutorial006b.py +++ b/tests/test_tutorial/test_custom_response/test_tutorial006b.py @@ -1,6 +1,6 @@ from fastapi.testclient import TestClient -from docs_src.custom_response.tutorial006b import app +from docs_src.custom_response.tutorial006b_py39 import app client = TestClient(app) diff --git a/tests/test_tutorial/test_custom_response/test_tutorial006c.py b/tests/test_tutorial/test_custom_response/test_tutorial006c.py index 2675f2a93c..e3f76c8403 100644 --- a/tests/test_tutorial/test_custom_response/test_tutorial006c.py +++ b/tests/test_tutorial/test_custom_response/test_tutorial006c.py @@ -1,6 +1,6 @@ from fastapi.testclient import TestClient -from docs_src.custom_response.tutorial006c import app +from docs_src.custom_response.tutorial006c_py39 import app client = TestClient(app) diff --git a/tests/test_tutorial/test_custom_response/test_tutorial007.py b/tests/test_tutorial/test_custom_response/test_tutorial007.py index 4ede820b94..a62476ec14 100644 --- a/tests/test_tutorial/test_custom_response/test_tutorial007.py +++ b/tests/test_tutorial/test_custom_response/test_tutorial007.py @@ -1,6 +1,6 @@ from fastapi.testclient import TestClient -from docs_src.custom_response.tutorial007 import app +from docs_src.custom_response.tutorial007_py39 import app client = TestClient(app) diff --git a/tests/test_tutorial/test_custom_response/test_tutorial008.py b/tests/test_tutorial/test_custom_response/test_tutorial008.py index 10d88a5948..d9fe61f539 100644 --- a/tests/test_tutorial/test_custom_response/test_tutorial008.py +++ b/tests/test_tutorial/test_custom_response/test_tutorial008.py @@ -2,15 +2,15 @@ from pathlib import Path from fastapi.testclient import TestClient -from docs_src.custom_response import tutorial008 -from docs_src.custom_response.tutorial008 import app +from docs_src.custom_response import tutorial008_py39 +from docs_src.custom_response.tutorial008_py39 import app client = TestClient(app) def test_get(tmp_path: Path): file_path: Path = tmp_path / "large-video-file.mp4" - tutorial008.some_file_path = str(file_path) + tutorial008_py39.some_file_path = str(file_path) test_content = b"Fake video bytes" file_path.write_bytes(test_content) response = client.get("/") diff --git a/tests/test_tutorial/test_custom_response/test_tutorial009.py b/tests/test_tutorial/test_custom_response/test_tutorial009.py index ac20f89e67..cb6a514be6 100644 --- a/tests/test_tutorial/test_custom_response/test_tutorial009.py +++ b/tests/test_tutorial/test_custom_response/test_tutorial009.py @@ -2,15 +2,15 @@ from pathlib import Path from fastapi.testclient import TestClient -from docs_src.custom_response import tutorial009 -from docs_src.custom_response.tutorial009 import app +from docs_src.custom_response import tutorial009_py39 +from docs_src.custom_response.tutorial009_py39 import app client = TestClient(app) def test_get(tmp_path: Path): file_path: Path = tmp_path / "large-video-file.mp4" - tutorial009.some_file_path = str(file_path) + tutorial009_py39.some_file_path = str(file_path) test_content = b"Fake video bytes" file_path.write_bytes(test_content) response = client.get("/") diff --git a/tests/test_tutorial/test_custom_response/test_tutorial009b.py b/tests/test_tutorial/test_custom_response/test_tutorial009b.py index 4f56e2f3fe..9918bdb1ac 100644 --- a/tests/test_tutorial/test_custom_response/test_tutorial009b.py +++ b/tests/test_tutorial/test_custom_response/test_tutorial009b.py @@ -2,15 +2,15 @@ from pathlib import Path from fastapi.testclient import TestClient -from docs_src.custom_response import tutorial009b -from docs_src.custom_response.tutorial009b import app +from docs_src.custom_response import tutorial009b_py39 +from docs_src.custom_response.tutorial009b_py39 import app client = TestClient(app) def test_get(tmp_path: Path): file_path: Path = tmp_path / "large-video-file.mp4" - tutorial009b.some_file_path = str(file_path) + tutorial009b_py39.some_file_path = str(file_path) test_content = b"Fake video bytes" file_path.write_bytes(test_content) response = client.get("/") diff --git a/tests/test_tutorial/test_custom_response/test_tutorial009c.py b/tests/test_tutorial/test_custom_response/test_tutorial009c.py index 23c711abe9..efc3a6b4a0 100644 --- a/tests/test_tutorial/test_custom_response/test_tutorial009c.py +++ b/tests/test_tutorial/test_custom_response/test_tutorial009c.py @@ -1,6 +1,6 @@ from fastapi.testclient import TestClient -from docs_src.custom_response.tutorial009c import app +from docs_src.custom_response.tutorial009c_py39 import app client = TestClient(app) diff --git a/tests/test_tutorial/test_dataclasses/test_tutorial001.py b/tests/test_tutorial/test_dataclasses/test_tutorial001.py index b36dee7684..d5f230bc42 100644 --- a/tests/test_tutorial/test_dataclasses/test_tutorial001.py +++ b/tests/test_tutorial/test_dataclasses/test_tutorial001.py @@ -10,7 +10,7 @@ from tests.utils import needs_py310 @pytest.fixture( name="client", params=[ - pytest.param("tutorial001"), + pytest.param("tutorial001_py39"), pytest.param("tutorial001_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_dataclasses/test_tutorial002.py b/tests/test_tutorial/test_dataclasses/test_tutorial002.py index baaea45d8f..4cf8933805 100644 --- a/tests/test_tutorial/test_dataclasses/test_tutorial002.py +++ b/tests/test_tutorial/test_dataclasses/test_tutorial002.py @@ -4,14 +4,13 @@ import pytest from dirty_equals import IsDict, IsOneOf from fastapi.testclient import TestClient -from tests.utils import needs_py39, needs_py310 +from tests.utils import needs_py310 @pytest.fixture( name="client", params=[ - pytest.param("tutorial002"), - pytest.param("tutorial002_py39", marks=needs_py39), + pytest.param("tutorial002_py39"), pytest.param("tutorial002_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_dataclasses/test_tutorial003.py b/tests/test_tutorial/test_dataclasses/test_tutorial003.py index 5728d2b6b3..d8cc45dd69 100644 --- a/tests/test_tutorial/test_dataclasses/test_tutorial003.py +++ b/tests/test_tutorial/test_dataclasses/test_tutorial003.py @@ -3,14 +3,13 @@ import importlib import pytest from fastapi.testclient import TestClient -from ...utils import needs_py39, needs_py310, needs_pydanticv1, needs_pydanticv2 +from ...utils import needs_py310, needs_pydanticv1, needs_pydanticv2 @pytest.fixture( name="client", params=[ - pytest.param("tutorial003"), - pytest.param("tutorial003_py39", marks=needs_py39), + pytest.param("tutorial003_py39"), pytest.param("tutorial003_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_dependencies/test_tutorial001.py b/tests/test_tutorial/test_dependencies/test_tutorial001.py index ed9944912e..8dac99cf30 100644 --- a/tests/test_tutorial/test_dependencies/test_tutorial001.py +++ b/tests/test_tutorial/test_dependencies/test_tutorial001.py @@ -4,16 +4,15 @@ import pytest from dirty_equals import IsDict from fastapi.testclient import TestClient -from ...utils import needs_py39, needs_py310 +from ...utils import needs_py310 @pytest.fixture( name="client", params=[ - "tutorial001", + pytest.param("tutorial001_py39"), pytest.param("tutorial001_py310", marks=needs_py310), - "tutorial001_an", - pytest.param("tutorial001_an_py39", marks=needs_py39), + pytest.param("tutorial001_an_py39"), pytest.param("tutorial001_an_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_dependencies/test_tutorial004.py b/tests/test_tutorial/test_dependencies/test_tutorial004.py index 8221c83d44..8a1346d0d2 100644 --- a/tests/test_tutorial/test_dependencies/test_tutorial004.py +++ b/tests/test_tutorial/test_dependencies/test_tutorial004.py @@ -4,16 +4,15 @@ import pytest from dirty_equals import IsDict from fastapi.testclient import TestClient -from ...utils import needs_py39, needs_py310 +from ...utils import needs_py310 @pytest.fixture( name="client", params=[ - "tutorial004", + pytest.param("tutorial004_py39"), pytest.param("tutorial004_py310", marks=needs_py310), - "tutorial004_an", - pytest.param("tutorial004_an_py39", marks=needs_py39), + pytest.param("tutorial004_an_py39"), pytest.param("tutorial004_an_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_dependencies/test_tutorial006.py b/tests/test_tutorial/test_dependencies/test_tutorial006.py index 4530762f76..46f0066f9f 100644 --- a/tests/test_tutorial/test_dependencies/test_tutorial006.py +++ b/tests/test_tutorial/test_dependencies/test_tutorial006.py @@ -4,15 +4,12 @@ import pytest from dirty_equals import IsDict from fastapi.testclient import TestClient -from ...utils import needs_py39 - @pytest.fixture( name="client", params=[ - "tutorial006", - "tutorial006_an", - pytest.param("tutorial006_an_py39", marks=needs_py39), + pytest.param("tutorial006_py39"), + pytest.param("tutorial006_an_py39"), ], ) def get_client(request: pytest.FixtureRequest): diff --git a/tests/test_tutorial/test_dependencies/test_tutorial008b.py b/tests/test_tutorial/test_dependencies/test_tutorial008b.py index 4d70922657..91e00b3705 100644 --- a/tests/test_tutorial/test_dependencies/test_tutorial008b.py +++ b/tests/test_tutorial/test_dependencies/test_tutorial008b.py @@ -3,15 +3,12 @@ import importlib import pytest from fastapi.testclient import TestClient -from ...utils import needs_py39 - @pytest.fixture( name="client", params=[ - "tutorial008b", - "tutorial008b_an", - pytest.param("tutorial008b_an_py39", marks=needs_py39), + pytest.param("tutorial008b_py39"), + pytest.param("tutorial008b_an_py39"), ], ) def get_client(request: pytest.FixtureRequest): diff --git a/tests/test_tutorial/test_dependencies/test_tutorial008c.py b/tests/test_tutorial/test_dependencies/test_tutorial008c.py index 369b0a221d..aede6f8d25 100644 --- a/tests/test_tutorial/test_dependencies/test_tutorial008c.py +++ b/tests/test_tutorial/test_dependencies/test_tutorial008c.py @@ -5,15 +5,12 @@ import pytest from fastapi.exceptions import FastAPIError from fastapi.testclient import TestClient -from ...utils import needs_py39 - @pytest.fixture( name="mod", params=[ - "tutorial008c", - "tutorial008c_an", - pytest.param("tutorial008c_an_py39", marks=needs_py39), + pytest.param("tutorial008c_py39"), + pytest.param("tutorial008c_an_py39"), ], ) def get_mod(request: pytest.FixtureRequest): diff --git a/tests/test_tutorial/test_dependencies/test_tutorial008d.py b/tests/test_tutorial/test_dependencies/test_tutorial008d.py index bc99bb3835..5477f8b953 100644 --- a/tests/test_tutorial/test_dependencies/test_tutorial008d.py +++ b/tests/test_tutorial/test_dependencies/test_tutorial008d.py @@ -4,15 +4,12 @@ from types import ModuleType import pytest from fastapi.testclient import TestClient -from ...utils import needs_py39 - @pytest.fixture( name="mod", params=[ - "tutorial008d", - "tutorial008d_an", - pytest.param("tutorial008d_an_py39", marks=needs_py39), + pytest.param("tutorial008d_py39"), + pytest.param("tutorial008d_an_py39"), ], ) def get_mod(request: pytest.FixtureRequest): diff --git a/tests/test_tutorial/test_dependencies/test_tutorial008e.py b/tests/test_tutorial/test_dependencies/test_tutorial008e.py index 1ae9ab2cd1..c433157ea1 100644 --- a/tests/test_tutorial/test_dependencies/test_tutorial008e.py +++ b/tests/test_tutorial/test_dependencies/test_tutorial008e.py @@ -3,15 +3,12 @@ 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), + pytest.param("tutorial008e_py39"), + pytest.param("tutorial008e_an_py39"), ], ) def get_client(request: pytest.FixtureRequest): diff --git a/tests/test_tutorial/test_dependencies/test_tutorial012.py b/tests/test_tutorial/test_dependencies/test_tutorial012.py index 0af17e9bc5..b791ee0aa1 100644 --- a/tests/test_tutorial/test_dependencies/test_tutorial012.py +++ b/tests/test_tutorial/test_dependencies/test_tutorial012.py @@ -4,15 +4,12 @@ import pytest from dirty_equals import IsDict from fastapi.testclient import TestClient -from ...utils import needs_py39 - @pytest.fixture( name="client", params=[ - "tutorial012", - "tutorial012_an", - pytest.param("tutorial012_an_py39", marks=needs_py39), + pytest.param("tutorial012_py39"), + pytest.param("tutorial012_an_py39"), ], ) def get_client(request: pytest.FixtureRequest): diff --git a/tests/test_tutorial/test_events/test_tutorial001.py b/tests/test_tutorial/test_events/test_tutorial001.py index f65b92d127..5fe99d50df 100644 --- a/tests/test_tutorial/test_events/test_tutorial001.py +++ b/tests/test_tutorial/test_events/test_tutorial001.py @@ -6,7 +6,7 @@ from fastapi.testclient import TestClient @pytest.fixture(name="app", scope="module") def get_app(): with pytest.warns(DeprecationWarning): - from docs_src.events.tutorial001 import app + from docs_src.events.tutorial001_py39 import app yield app diff --git a/tests/test_tutorial/test_events/test_tutorial002.py b/tests/test_tutorial/test_events/test_tutorial002.py index 137294d737..0612899b55 100644 --- a/tests/test_tutorial/test_events/test_tutorial002.py +++ b/tests/test_tutorial/test_events/test_tutorial002.py @@ -6,7 +6,7 @@ from fastapi.testclient import TestClient @pytest.fixture(name="app", scope="module") def get_app(): with pytest.warns(DeprecationWarning): - from docs_src.events.tutorial002 import app + from docs_src.events.tutorial002_py39 import app yield app diff --git a/tests/test_tutorial/test_events/test_tutorial003.py b/tests/test_tutorial/test_events/test_tutorial003.py index 0ad1a1f8b2..38710edfea 100644 --- a/tests/test_tutorial/test_events/test_tutorial003.py +++ b/tests/test_tutorial/test_events/test_tutorial003.py @@ -1,6 +1,6 @@ from fastapi.testclient import TestClient -from docs_src.events.tutorial003 import ( +from docs_src.events.tutorial003_py39 import ( app, fake_answer_to_everything_ml_model, ml_models, diff --git a/tests/test_tutorial/test_extending_openapi/test_tutorial001.py b/tests/test_tutorial/test_extending_openapi/test_tutorial001.py index a85a313501..83ecb300ee 100644 --- a/tests/test_tutorial/test_extending_openapi/test_tutorial001.py +++ b/tests/test_tutorial/test_extending_openapi/test_tutorial001.py @@ -1,6 +1,6 @@ from fastapi.testclient import TestClient -from docs_src.extending_openapi.tutorial001 import app +from docs_src.extending_openapi.tutorial001_py39 import app client = TestClient(app) diff --git a/tests/test_tutorial/test_extra_data_types/test_tutorial001.py b/tests/test_tutorial/test_extra_data_types/test_tutorial001.py index b816c9cab5..e11f73fe35 100644 --- a/tests/test_tutorial/test_extra_data_types/test_tutorial001.py +++ b/tests/test_tutorial/test_extra_data_types/test_tutorial001.py @@ -4,16 +4,15 @@ import pytest from dirty_equals import IsDict from fastapi.testclient import TestClient -from ...utils import needs_py39, needs_py310 +from ...utils import needs_py310 @pytest.fixture( name="client", params=[ - "tutorial001", + pytest.param("tutorial001_py39"), pytest.param("tutorial001_py310", marks=needs_py310), - "tutorial001_an", - pytest.param("tutorial001_an_py39", marks=needs_py39), + pytest.param("tutorial001_an_py39"), pytest.param("tutorial001_an_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_extra_models/test_tutorial003.py b/tests/test_tutorial/test_extra_models/test_tutorial003.py index 73aa299039..3aa83c0c40 100644 --- a/tests/test_tutorial/test_extra_models/test_tutorial003.py +++ b/tests/test_tutorial/test_extra_models/test_tutorial003.py @@ -10,7 +10,7 @@ from ...utils import needs_py310 @pytest.fixture( name="client", params=[ - "tutorial003", + pytest.param("tutorial003_py39"), pytest.param("tutorial003_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_extra_models/test_tutorial004.py b/tests/test_tutorial/test_extra_models/test_tutorial004.py index 7628db30c7..073375ccc9 100644 --- a/tests/test_tutorial/test_extra_models/test_tutorial004.py +++ b/tests/test_tutorial/test_extra_models/test_tutorial004.py @@ -3,14 +3,11 @@ import importlib import pytest from fastapi.testclient import TestClient -from ...utils import needs_py39 - @pytest.fixture( name="client", params=[ - "tutorial004", - pytest.param("tutorial004_py39", marks=needs_py39), + pytest.param("tutorial004_py39"), ], ) def get_client(request: pytest.FixtureRequest): diff --git a/tests/test_tutorial/test_extra_models/test_tutorial005.py b/tests/test_tutorial/test_extra_models/test_tutorial005.py index 553e442385..8e52d8d4ba 100644 --- a/tests/test_tutorial/test_extra_models/test_tutorial005.py +++ b/tests/test_tutorial/test_extra_models/test_tutorial005.py @@ -3,14 +3,11 @@ import importlib import pytest from fastapi.testclient import TestClient -from ...utils import needs_py39 - @pytest.fixture( name="client", params=[ - "tutorial005", - pytest.param("tutorial005_py39", marks=needs_py39), + pytest.param("tutorial005_py39"), ], ) def get_client(request: pytest.FixtureRequest): diff --git a/tests/test_tutorial/test_first_steps/test_tutorial001.py b/tests/test_tutorial/test_first_steps/test_tutorial001.py index 6cc9fc2282..c102bb9999 100644 --- a/tests/test_tutorial/test_first_steps/test_tutorial001.py +++ b/tests/test_tutorial/test_first_steps/test_tutorial001.py @@ -1,7 +1,7 @@ import pytest from fastapi.testclient import TestClient -from docs_src.first_steps.tutorial001 import app +from docs_src.first_steps.tutorial001_py39 import app client = TestClient(app) diff --git a/tests/test_tutorial/test_generate_clients/test_tutorial003.py b/tests/test_tutorial/test_generate_clients/test_tutorial003.py index 1cd9678a1c..bac52e4fd6 100644 --- a/tests/test_tutorial/test_generate_clients/test_tutorial003.py +++ b/tests/test_tutorial/test_generate_clients/test_tutorial003.py @@ -1,6 +1,6 @@ from fastapi.testclient import TestClient -from docs_src.generate_clients.tutorial003 import app +from docs_src.generate_clients.tutorial003_py39 import app client = TestClient(app) diff --git a/tests/test_tutorial/test_handling_errors/test_tutorial001.py b/tests/test_tutorial/test_handling_errors/test_tutorial001.py index 8809c135bd..c01850fae6 100644 --- a/tests/test_tutorial/test_handling_errors/test_tutorial001.py +++ b/tests/test_tutorial/test_handling_errors/test_tutorial001.py @@ -1,6 +1,6 @@ from fastapi.testclient import TestClient -from docs_src.handling_errors.tutorial001 import app +from docs_src.handling_errors.tutorial001_py39 import app client = TestClient(app) diff --git a/tests/test_tutorial/test_handling_errors/test_tutorial002.py b/tests/test_tutorial/test_handling_errors/test_tutorial002.py index efd86ebdec..09366a86fa 100644 --- a/tests/test_tutorial/test_handling_errors/test_tutorial002.py +++ b/tests/test_tutorial/test_handling_errors/test_tutorial002.py @@ -1,6 +1,6 @@ from fastapi.testclient import TestClient -from docs_src.handling_errors.tutorial002 import app +from docs_src.handling_errors.tutorial002_py39 import app client = TestClient(app) diff --git a/tests/test_tutorial/test_handling_errors/test_tutorial003.py b/tests/test_tutorial/test_handling_errors/test_tutorial003.py index 4763f68f3f..51ac3e7b28 100644 --- a/tests/test_tutorial/test_handling_errors/test_tutorial003.py +++ b/tests/test_tutorial/test_handling_errors/test_tutorial003.py @@ -1,6 +1,6 @@ from fastapi.testclient import TestClient -from docs_src.handling_errors.tutorial003 import app +from docs_src.handling_errors.tutorial003_py39 import app client = TestClient(app) diff --git a/tests/test_tutorial/test_handling_errors/test_tutorial004.py b/tests/test_tutorial/test_handling_errors/test_tutorial004.py index c04bf37245..376bc8266f 100644 --- a/tests/test_tutorial/test_handling_errors/test_tutorial004.py +++ b/tests/test_tutorial/test_handling_errors/test_tutorial004.py @@ -1,6 +1,6 @@ from fastapi.testclient import TestClient -from docs_src.handling_errors.tutorial004 import app +from docs_src.handling_errors.tutorial004_py39 import app client = TestClient(app) diff --git a/tests/test_tutorial/test_handling_errors/test_tutorial005.py b/tests/test_tutorial/test_handling_errors/test_tutorial005.py index 581b2e4c75..d713c5d876 100644 --- a/tests/test_tutorial/test_handling_errors/test_tutorial005.py +++ b/tests/test_tutorial/test_handling_errors/test_tutorial005.py @@ -1,7 +1,7 @@ from dirty_equals import IsDict from fastapi.testclient import TestClient -from docs_src.handling_errors.tutorial005 import app +from docs_src.handling_errors.tutorial005_py39 import app client = TestClient(app) diff --git a/tests/test_tutorial/test_handling_errors/test_tutorial006.py b/tests/test_tutorial/test_handling_errors/test_tutorial006.py index 7d2f553aac..491e461b3d 100644 --- a/tests/test_tutorial/test_handling_errors/test_tutorial006.py +++ b/tests/test_tutorial/test_handling_errors/test_tutorial006.py @@ -1,7 +1,7 @@ from dirty_equals import IsDict from fastapi.testclient import TestClient -from docs_src.handling_errors.tutorial006 import app +from docs_src.handling_errors.tutorial006_py39 import app client = TestClient(app) diff --git a/tests/test_tutorial/test_header_param_models/test_tutorial001.py b/tests/test_tutorial/test_header_param_models/test_tutorial001.py index bc876897b2..f59d50762c 100644 --- a/tests/test_tutorial/test_header_param_models/test_tutorial001.py +++ b/tests/test_tutorial/test_header_param_models/test_tutorial001.py @@ -5,17 +5,15 @@ from dirty_equals import IsDict from fastapi.testclient import TestClient from inline_snapshot import snapshot -from tests.utils import needs_py39, needs_py310 +from tests.utils import needs_py310 @pytest.fixture( name="client", params=[ - "tutorial001", - pytest.param("tutorial001_py39", marks=needs_py39), + pytest.param("tutorial001_py39"), pytest.param("tutorial001_py310", marks=needs_py310), - "tutorial001_an", - pytest.param("tutorial001_an_py39", marks=needs_py39), + pytest.param("tutorial001_an_py39"), pytest.param("tutorial001_an_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_header_param_models/test_tutorial002.py b/tests/test_tutorial/test_header_param_models/test_tutorial002.py index 0615521c43..a7a271ba41 100644 --- a/tests/test_tutorial/test_header_param_models/test_tutorial002.py +++ b/tests/test_tutorial/test_header_param_models/test_tutorial002.py @@ -5,21 +5,19 @@ from dirty_equals import IsDict from fastapi.testclient import TestClient from inline_snapshot import snapshot -from tests.utils import needs_py39, needs_py310, needs_pydanticv1, needs_pydanticv2 +from tests.utils import needs_py310, needs_pydanticv1, needs_pydanticv2 @pytest.fixture( name="client", params=[ - pytest.param("tutorial002", marks=needs_pydanticv2), + pytest.param("tutorial002_py39", marks=needs_pydanticv2), pytest.param("tutorial002_py310", marks=[needs_py310, needs_pydanticv2]), - pytest.param("tutorial002_an", marks=needs_pydanticv2), - pytest.param("tutorial002_an_py39", marks=[needs_py39, needs_pydanticv2]), + pytest.param("tutorial002_an_py39", marks=needs_pydanticv2), pytest.param("tutorial002_an_py310", marks=[needs_py310, needs_pydanticv2]), - pytest.param("tutorial002_pv1", marks=[needs_pydanticv1, needs_pydanticv1]), + pytest.param("tutorial002_pv1_py39", marks=needs_pydanticv1), pytest.param("tutorial002_pv1_py310", marks=[needs_py310, needs_pydanticv1]), - pytest.param("tutorial002_pv1_an", marks=[needs_pydanticv1]), - pytest.param("tutorial002_pv1_an_py39", marks=[needs_py39, needs_pydanticv1]), + pytest.param("tutorial002_pv1_an_py39", marks=needs_pydanticv1), pytest.param("tutorial002_pv1_an_py310", marks=[needs_py310, needs_pydanticv1]), ], ) diff --git a/tests/test_tutorial/test_header_param_models/test_tutorial003.py b/tests/test_tutorial/test_header_param_models/test_tutorial003.py index 554a48d2e8..947587504f 100644 --- a/tests/test_tutorial/test_header_param_models/test_tutorial003.py +++ b/tests/test_tutorial/test_header_param_models/test_tutorial003.py @@ -5,17 +5,15 @@ from dirty_equals import IsDict from fastapi.testclient import TestClient from inline_snapshot import snapshot -from tests.utils import needs_py39, needs_py310 +from tests.utils import needs_py310 @pytest.fixture( name="client", params=[ - "tutorial003", - pytest.param("tutorial003_py39", marks=needs_py39), + pytest.param("tutorial003_py39"), pytest.param("tutorial003_py310", marks=needs_py310), - "tutorial003_an", - pytest.param("tutorial003_an_py39", marks=needs_py39), + pytest.param("tutorial003_an_py39"), pytest.param("tutorial003_an_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_header_params/test_tutorial001.py b/tests/test_tutorial/test_header_params/test_tutorial001.py index d6f7fe6189..beaf917f92 100644 --- a/tests/test_tutorial/test_header_params/test_tutorial001.py +++ b/tests/test_tutorial/test_header_params/test_tutorial001.py @@ -10,9 +10,9 @@ from ...utils import needs_py310 @pytest.fixture( name="client", params=[ - "tutorial001", + pytest.param("tutorial001_py39"), pytest.param("tutorial001_py310", marks=needs_py310), - "tutorial001_an", + pytest.param("tutorial001_an_py39"), pytest.param("tutorial001_an_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_header_params/test_tutorial002.py b/tests/test_tutorial/test_header_params/test_tutorial002.py index 7158f8651b..b892ff905f 100644 --- a/tests/test_tutorial/test_header_params/test_tutorial002.py +++ b/tests/test_tutorial/test_header_params/test_tutorial002.py @@ -4,16 +4,15 @@ import pytest from dirty_equals import IsDict from fastapi.testclient import TestClient -from ...utils import needs_py39, needs_py310 +from ...utils import needs_py310 @pytest.fixture( name="client", params=[ - "tutorial002", + pytest.param("tutorial002_py39"), pytest.param("tutorial002_py310", marks=needs_py310), - "tutorial002_an", - pytest.param("tutorial002_an_py39", marks=needs_py39), + pytest.param("tutorial002_an_py39"), pytest.param("tutorial002_an_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_header_params/test_tutorial003.py b/tests/test_tutorial/test_header_params/test_tutorial003.py index 473b961236..ef76244159 100644 --- a/tests/test_tutorial/test_header_params/test_tutorial003.py +++ b/tests/test_tutorial/test_header_params/test_tutorial003.py @@ -4,16 +4,15 @@ import pytest from dirty_equals import IsDict from fastapi.testclient import TestClient -from ...utils import needs_py39, needs_py310 +from ...utils import needs_py310 @pytest.fixture( name="client", params=[ - "tutorial003", + pytest.param("tutorial003_py39"), pytest.param("tutorial003_py310", marks=needs_py310), - "tutorial003_an", - pytest.param("tutorial003_an_py39", marks=needs_py39), + pytest.param("tutorial003_an_py39"), pytest.param("tutorial003_an_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_metadata/test_tutorial001.py b/tests/test_tutorial/test_metadata/test_tutorial001.py index 04e8ff82b0..ead48577d0 100644 --- a/tests/test_tutorial/test_metadata/test_tutorial001.py +++ b/tests/test_tutorial/test_metadata/test_tutorial001.py @@ -1,6 +1,6 @@ from fastapi.testclient import TestClient -from docs_src.metadata.tutorial001 import app +from docs_src.metadata.tutorial001_py39 import app client = TestClient(app) diff --git a/tests/test_tutorial/test_metadata/test_tutorial001_1.py b/tests/test_tutorial/test_metadata/test_tutorial001_1.py index 3efb1c4329..40878ccfd4 100644 --- a/tests/test_tutorial/test_metadata/test_tutorial001_1.py +++ b/tests/test_tutorial/test_metadata/test_tutorial001_1.py @@ -1,6 +1,6 @@ from fastapi.testclient import TestClient -from docs_src.metadata.tutorial001_1 import app +from docs_src.metadata.tutorial001_1_py39 import app client = TestClient(app) diff --git a/tests/test_tutorial/test_metadata/test_tutorial004.py b/tests/test_tutorial/test_metadata/test_tutorial004.py index 5072203712..4ef93fd5e3 100644 --- a/tests/test_tutorial/test_metadata/test_tutorial004.py +++ b/tests/test_tutorial/test_metadata/test_tutorial004.py @@ -1,6 +1,6 @@ from fastapi.testclient import TestClient -from docs_src.metadata.tutorial004 import app +from docs_src.metadata.tutorial004_py39 import app client = TestClient(app) diff --git a/tests/test_tutorial/test_openapi_callbacks/test_tutorial001.py b/tests/test_tutorial/test_openapi_callbacks/test_tutorial001.py index 2df2b98893..975e07cbdd 100644 --- a/tests/test_tutorial/test_openapi_callbacks/test_tutorial001.py +++ b/tests/test_tutorial/test_openapi_callbacks/test_tutorial001.py @@ -11,7 +11,7 @@ from tests.utils import needs_py310 @pytest.fixture( name="mod", params=[ - pytest.param("tutorial001"), + pytest.param("tutorial001_py39"), pytest.param("tutorial001_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_openapi_webhooks/test_tutorial001.py b/tests/test_tutorial/test_openapi_webhooks/test_tutorial001.py index dc67ec401d..27619489fa 100644 --- a/tests/test_tutorial/test_openapi_webhooks/test_tutorial001.py +++ b/tests/test_tutorial/test_openapi_webhooks/test_tutorial001.py @@ -1,6 +1,6 @@ from fastapi.testclient import TestClient -from docs_src.openapi_webhooks.tutorial001 import app +from docs_src.openapi_webhooks.tutorial001_py39 import app client = TestClient(app) diff --git a/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial001.py b/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial001.py index 95542398e4..ee0b707108 100644 --- a/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial001.py +++ b/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial001.py @@ -1,6 +1,6 @@ from fastapi.testclient import TestClient -from docs_src.path_operation_advanced_configuration.tutorial001 import app +from docs_src.path_operation_advanced_configuration.tutorial001_py39 import app client = TestClient(app) diff --git a/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial002.py b/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial002.py index d1388c3670..f6580d72e3 100644 --- a/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial002.py +++ b/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial002.py @@ -1,6 +1,6 @@ from fastapi.testclient import TestClient -from docs_src.path_operation_advanced_configuration.tutorial002 import app +from docs_src.path_operation_advanced_configuration.tutorial002_py39 import app client = TestClient(app) diff --git a/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial003.py b/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial003.py index 313bb2a04a..104554fce3 100644 --- a/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial003.py +++ b/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial003.py @@ -1,6 +1,6 @@ from fastapi.testclient import TestClient -from docs_src.path_operation_advanced_configuration.tutorial003 import app +from docs_src.path_operation_advanced_configuration.tutorial003_py39 import app client = TestClient(app) diff --git a/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial004.py b/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial004.py index da5782d189..3805536e76 100644 --- a/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial004.py +++ b/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial004.py @@ -3,14 +3,13 @@ import importlib import pytest from fastapi.testclient import TestClient -from ...utils import needs_py39, needs_py310, needs_pydanticv1, needs_pydanticv2 +from ...utils import needs_py310, needs_pydanticv1, needs_pydanticv2 @pytest.fixture( name="client", params=[ - pytest.param("tutorial004"), - pytest.param("tutorial004_py39", marks=needs_py39), + pytest.param("tutorial004_py39"), pytest.param("tutorial004_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial005.py b/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial005.py index 07e2d7d202..e2a71236ff 100644 --- a/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial005.py +++ b/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial005.py @@ -1,6 +1,6 @@ from fastapi.testclient import TestClient -from docs_src.path_operation_advanced_configuration.tutorial005 import app +from docs_src.path_operation_advanced_configuration.tutorial005_py39 import app client = TestClient(app) diff --git a/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial006.py b/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial006.py index f92c59015e..9484f7f573 100644 --- a/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial006.py +++ b/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial006.py @@ -1,6 +1,6 @@ from fastapi.testclient import TestClient -from docs_src.path_operation_advanced_configuration.tutorial006 import app +from docs_src.path_operation_advanced_configuration.tutorial006_py39 import app client = TestClient(app) diff --git a/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial007.py b/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial007.py index a90337a63d..204cca09ed 100644 --- a/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial007.py +++ b/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial007.py @@ -3,14 +3,13 @@ import importlib import pytest from fastapi.testclient import TestClient -from ...utils import needs_py39, needs_pydanticv2 +from ...utils import needs_pydanticv2 @pytest.fixture( name="client", params=[ - pytest.param("tutorial007"), - pytest.param("tutorial007_py39", marks=needs_py39), + pytest.param("tutorial007_py39"), ], ) def get_client(request: pytest.FixtureRequest): diff --git a/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial007_pv1.py b/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial007_pv1.py index b38e4947cc..62b67a98c1 100644 --- a/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial007_pv1.py +++ b/tests/test_tutorial/test_path_operation_advanced_configurations/test_tutorial007_pv1.py @@ -3,14 +3,13 @@ import importlib import pytest from fastapi.testclient import TestClient -from ...utils import needs_py39, needs_pydanticv1 +from ...utils import needs_pydanticv1 @pytest.fixture( name="client", params=[ - pytest.param("tutorial007_pv1"), - pytest.param("tutorial007_pv1_py39", marks=needs_py39), + pytest.param("tutorial007_pv1_py39"), ], ) def get_client(request: pytest.FixtureRequest): diff --git a/tests/test_tutorial/test_path_operation_configurations/test_tutorial002b.py b/tests/test_tutorial/test_path_operation_configurations/test_tutorial002b.py index 58dec5769d..5a0193adfa 100644 --- a/tests/test_tutorial/test_path_operation_configurations/test_tutorial002b.py +++ b/tests/test_tutorial/test_path_operation_configurations/test_tutorial002b.py @@ -1,6 +1,6 @@ from fastapi.testclient import TestClient -from docs_src.path_operation_configuration.tutorial002b import app +from docs_src.path_operation_configuration.tutorial002b_py39 import app client = TestClient(app) diff --git a/tests/test_tutorial/test_path_operation_configurations/test_tutorial005.py b/tests/test_tutorial/test_path_operation_configurations/test_tutorial005.py index 0742f5d0e8..2a7a2b78b2 100644 --- a/tests/test_tutorial/test_path_operation_configurations/test_tutorial005.py +++ b/tests/test_tutorial/test_path_operation_configurations/test_tutorial005.py @@ -3,14 +3,13 @@ import importlib import pytest from fastapi.testclient import TestClient -from ...utils import needs_py39, needs_py310, needs_pydanticv1, needs_pydanticv2 +from ...utils import needs_py310, needs_pydanticv1, needs_pydanticv2 @pytest.fixture( name="client", params=[ - "tutorial005", - pytest.param("tutorial005_py39", marks=needs_py39), + pytest.param("tutorial005_py39"), pytest.param("tutorial005_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_path_operation_configurations/test_tutorial006.py b/tests/test_tutorial/test_path_operation_configurations/test_tutorial006.py index 91180d1097..5d9c55675f 100644 --- a/tests/test_tutorial/test_path_operation_configurations/test_tutorial006.py +++ b/tests/test_tutorial/test_path_operation_configurations/test_tutorial006.py @@ -1,7 +1,7 @@ import pytest from fastapi.testclient import TestClient -from docs_src.path_operation_configuration.tutorial006 import app +from docs_src.path_operation_configuration.tutorial006_py39 import app client = TestClient(app) diff --git a/tests/test_tutorial/test_path_params/test_tutorial004.py b/tests/test_tutorial/test_path_params/test_tutorial004.py index acbeaca769..f7f233ccff 100644 --- a/tests/test_tutorial/test_path_params/test_tutorial004.py +++ b/tests/test_tutorial/test_path_params/test_tutorial004.py @@ -1,6 +1,6 @@ from fastapi.testclient import TestClient -from docs_src.path_params.tutorial004 import app +from docs_src.path_params.tutorial004_py39 import app client = TestClient(app) diff --git a/tests/test_tutorial/test_path_params/test_tutorial005.py b/tests/test_tutorial/test_path_params/test_tutorial005.py index 2e4b0146be..b3be70471a 100644 --- a/tests/test_tutorial/test_path_params/test_tutorial005.py +++ b/tests/test_tutorial/test_path_params/test_tutorial005.py @@ -1,7 +1,7 @@ from dirty_equals import IsDict from fastapi.testclient import TestClient -from docs_src.path_params.tutorial005 import app +from docs_src.path_params.tutorial005_py39 import app client = TestClient(app) diff --git a/tests/test_tutorial/test_pydantic_v1_in_v2/test_tutorial001.py b/tests/test_tutorial/test_pydantic_v1_in_v2/test_tutorial001.py index 3075a05f51..ce53a36eb8 100644 --- a/tests/test_tutorial/test_pydantic_v1_in_v2/test_tutorial001.py +++ b/tests/test_tutorial/test_pydantic_v1_in_v2/test_tutorial001.py @@ -23,7 +23,7 @@ from ...utils import needs_py310 @pytest.fixture( name="mod", params=[ - "tutorial001_an", + "tutorial001_an_py39", pytest.param("tutorial001_an_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_pydantic_v1_in_v2/test_tutorial002.py b/tests/test_tutorial/test_pydantic_v1_in_v2/test_tutorial002.py index a402c663d1..57720bf489 100644 --- a/tests/test_tutorial/test_pydantic_v1_in_v2/test_tutorial002.py +++ b/tests/test_tutorial/test_pydantic_v1_in_v2/test_tutorial002.py @@ -24,7 +24,7 @@ from ...utils import needs_py310 @pytest.fixture( name="client", params=[ - "tutorial002_an", + "tutorial002_an_py39", pytest.param("tutorial002_an_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_pydantic_v1_in_v2/test_tutorial003.py b/tests/test_tutorial/test_pydantic_v1_in_v2/test_tutorial003.py index 03155c9249..f020d4a975 100644 --- a/tests/test_tutorial/test_pydantic_v1_in_v2/test_tutorial003.py +++ b/tests/test_tutorial/test_pydantic_v1_in_v2/test_tutorial003.py @@ -23,7 +23,7 @@ from ...utils import needs_py310 @pytest.fixture( name="client", params=[ - "tutorial003_an", + "tutorial003_an_py39", pytest.param("tutorial003_an_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_pydantic_v1_in_v2/test_tutorial004.py b/tests/test_tutorial/test_pydantic_v1_in_v2/test_tutorial004.py index d2e204ddaf..daa6f0b050 100644 --- a/tests/test_tutorial/test_pydantic_v1_in_v2/test_tutorial004.py +++ b/tests/test_tutorial/test_pydantic_v1_in_v2/test_tutorial004.py @@ -17,14 +17,13 @@ import importlib from fastapi.testclient import TestClient -from ...utils import needs_py39, needs_py310 +from ...utils import needs_py310 @pytest.fixture( name="client", params=[ - "tutorial004_an", - pytest.param("tutorial004_an_py39", marks=needs_py39), + pytest.param("tutorial004_an_py39"), pytest.param("tutorial004_an_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_query_param_models/test_tutorial001.py b/tests/test_tutorial/test_query_param_models/test_tutorial001.py index 5b7bc7b424..86830b9341 100644 --- a/tests/test_tutorial/test_query_param_models/test_tutorial001.py +++ b/tests/test_tutorial/test_query_param_models/test_tutorial001.py @@ -5,17 +5,15 @@ from dirty_equals import IsDict from fastapi.testclient import TestClient from inline_snapshot import snapshot -from tests.utils import needs_py39, needs_py310 +from tests.utils import needs_py310 @pytest.fixture( name="client", params=[ - "tutorial001", - pytest.param("tutorial001_py39", marks=needs_py39), + pytest.param("tutorial001_py39"), pytest.param("tutorial001_py310", marks=needs_py310), - "tutorial001_an", - pytest.param("tutorial001_an_py39", marks=needs_py39), + pytest.param("tutorial001_an_py39"), pytest.param("tutorial001_an_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_query_param_models/test_tutorial002.py b/tests/test_tutorial/test_query_param_models/test_tutorial002.py index 4432c9d8a3..e7de73f804 100644 --- a/tests/test_tutorial/test_query_param_models/test_tutorial002.py +++ b/tests/test_tutorial/test_query_param_models/test_tutorial002.py @@ -5,23 +5,19 @@ from dirty_equals import IsDict from fastapi.testclient import TestClient from inline_snapshot import snapshot -from tests.utils import needs_py39, needs_py310, needs_pydanticv1, needs_pydanticv2 +from tests.utils import needs_py310, needs_pydanticv1, needs_pydanticv2 @pytest.fixture( name="client", params=[ - pytest.param("tutorial002", marks=needs_pydanticv2), - pytest.param("tutorial002_py39", marks=[needs_py39, needs_pydanticv2]), + pytest.param("tutorial002_py39", marks=needs_pydanticv2), pytest.param("tutorial002_py310", marks=[needs_py310, needs_pydanticv2]), - pytest.param("tutorial002_an", marks=needs_pydanticv2), - pytest.param("tutorial002_an_py39", marks=[needs_py39, needs_pydanticv2]), + pytest.param("tutorial002_an_py39", marks=needs_pydanticv2), pytest.param("tutorial002_an_py310", marks=[needs_py310, needs_pydanticv2]), - pytest.param("tutorial002_pv1", marks=[needs_pydanticv1, needs_pydanticv1]), - pytest.param("tutorial002_pv1_py39", marks=[needs_py39, needs_pydanticv1]), + pytest.param("tutorial002_pv1_py39", marks=needs_pydanticv1), pytest.param("tutorial002_pv1_py310", marks=[needs_py310, needs_pydanticv1]), - pytest.param("tutorial002_pv1_an", marks=[needs_pydanticv1]), - pytest.param("tutorial002_pv1_an_py39", marks=[needs_py39, needs_pydanticv1]), + pytest.param("tutorial002_pv1_an_py39", marks=needs_pydanticv1), pytest.param("tutorial002_pv1_an_py310", marks=[needs_py310, needs_pydanticv1]), ], ) diff --git a/tests/test_tutorial/test_query_params/test_tutorial005.py b/tests/test_tutorial/test_query_params/test_tutorial005.py index 05ae85b451..ad4e4efa6b 100644 --- a/tests/test_tutorial/test_query_params/test_tutorial005.py +++ b/tests/test_tutorial/test_query_params/test_tutorial005.py @@ -1,7 +1,7 @@ from dirty_equals import IsDict from fastapi.testclient import TestClient -from docs_src.query_params.tutorial005 import app +from docs_src.query_params.tutorial005_py39 import app client = TestClient(app) diff --git a/tests/test_tutorial/test_query_params/test_tutorial006.py b/tests/test_tutorial/test_query_params/test_tutorial006.py index a0b5ef4943..349f8dd223 100644 --- a/tests/test_tutorial/test_query_params/test_tutorial006.py +++ b/tests/test_tutorial/test_query_params/test_tutorial006.py @@ -10,7 +10,7 @@ from ...utils import needs_py310 @pytest.fixture( name="client", params=[ - "tutorial006", + pytest.param("tutorial006_py39"), pytest.param("tutorial006_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_query_params_str_validations/test_tutorial010.py b/tests/test_tutorial/test_query_params_str_validations/test_tutorial010.py index e08e169633..de5dbbb2ee 100644 --- a/tests/test_tutorial/test_query_params_str_validations/test_tutorial010.py +++ b/tests/test_tutorial/test_query_params_str_validations/test_tutorial010.py @@ -5,16 +5,15 @@ from dirty_equals import IsDict from fastapi._compat import PYDANTIC_VERSION_MINOR_TUPLE from fastapi.testclient import TestClient -from ...utils import needs_py39, needs_py310 +from ...utils import needs_py310 @pytest.fixture( name="client", params=[ - "tutorial010", + pytest.param("tutorial010_py39"), pytest.param("tutorial010_py310", marks=needs_py310), - "tutorial010_an", - pytest.param("tutorial010_an_py39", marks=needs_py39), + pytest.param("tutorial010_an_py39"), pytest.param("tutorial010_an_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_query_params_str_validations/test_tutorial011.py b/tests/test_tutorial/test_query_params_str_validations/test_tutorial011.py index f4da25752b..50b3c5683c 100644 --- a/tests/test_tutorial/test_query_params_str_validations/test_tutorial011.py +++ b/tests/test_tutorial/test_query_params_str_validations/test_tutorial011.py @@ -4,17 +4,15 @@ import pytest from dirty_equals import IsDict from fastapi.testclient import TestClient -from ...utils import needs_py39, needs_py310 +from ...utils import needs_py310 @pytest.fixture( name="client", params=[ - "tutorial011", - pytest.param("tutorial011_py39", marks=needs_py310), + pytest.param("tutorial011_py39"), pytest.param("tutorial011_py310", marks=needs_py310), - "tutorial011_an", - pytest.param("tutorial011_an_py39", marks=needs_py39), + pytest.param("tutorial011_an_py39"), pytest.param("tutorial011_an_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_query_params_str_validations/test_tutorial012.py b/tests/test_tutorial/test_query_params_str_validations/test_tutorial012.py index 549a90519e..1826928611 100644 --- a/tests/test_tutorial/test_query_params_str_validations/test_tutorial012.py +++ b/tests/test_tutorial/test_query_params_str_validations/test_tutorial012.py @@ -3,16 +3,12 @@ import importlib import pytest from fastapi.testclient import TestClient -from ...utils import needs_py39 - @pytest.fixture( name="client", params=[ - "tutorial012", - pytest.param("tutorial012_py39", marks=needs_py39), - "tutorial012_an", - pytest.param("tutorial012_an_py39", marks=needs_py39), + pytest.param("tutorial012_py39"), + pytest.param("tutorial012_an_py39"), ], ) def get_client(request: pytest.FixtureRequest): diff --git a/tests/test_tutorial/test_query_params_str_validations/test_tutorial013.py b/tests/test_tutorial/test_query_params_str_validations/test_tutorial013.py index f2f5f7a858..46c367c86b 100644 --- a/tests/test_tutorial/test_query_params_str_validations/test_tutorial013.py +++ b/tests/test_tutorial/test_query_params_str_validations/test_tutorial013.py @@ -3,15 +3,12 @@ import importlib import pytest from fastapi.testclient import TestClient -from ...utils import needs_py39 - @pytest.fixture( name="client", params=[ - "tutorial013", - "tutorial013_an", - pytest.param("tutorial013_an_py39", marks=needs_py39), + "tutorial013_py39", + "tutorial013_an_py39", ], ) def get_client(request: pytest.FixtureRequest): diff --git a/tests/test_tutorial/test_query_params_str_validations/test_tutorial014.py b/tests/test_tutorial/test_query_params_str_validations/test_tutorial014.py index edd40bb1ab..0feaccfa44 100644 --- a/tests/test_tutorial/test_query_params_str_validations/test_tutorial014.py +++ b/tests/test_tutorial/test_query_params_str_validations/test_tutorial014.py @@ -3,16 +3,15 @@ import importlib import pytest from fastapi.testclient import TestClient -from ...utils import needs_py39, needs_py310 +from ...utils import needs_py310 @pytest.fixture( name="client", params=[ - "tutorial014", + pytest.param("tutorial014_py39"), pytest.param("tutorial014_py310", marks=needs_py310), - "tutorial014_an", - pytest.param("tutorial014_an_py39", marks=needs_py39), + pytest.param("tutorial014_an_py39"), pytest.param("tutorial014_an_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_query_params_str_validations/test_tutorial015.py b/tests/test_tutorial/test_query_params_str_validations/test_tutorial015.py index ae1c40286d..50ebf711f5 100644 --- a/tests/test_tutorial/test_query_params_str_validations/test_tutorial015.py +++ b/tests/test_tutorial/test_query_params_str_validations/test_tutorial015.py @@ -5,15 +5,14 @@ from dirty_equals import IsStr from fastapi.testclient import TestClient from inline_snapshot import snapshot -from ...utils import needs_py39, needs_py310, needs_pydanticv2 +from ...utils import needs_py310, needs_pydanticv2 @pytest.fixture( name="client", params=[ - pytest.param("tutorial015_an", marks=needs_pydanticv2), + pytest.param("tutorial015_an_py39", marks=needs_pydanticv2), pytest.param("tutorial015_an_py310", marks=(needs_py310, needs_pydanticv2)), - pytest.param("tutorial015_an_py39", marks=(needs_py39, needs_pydanticv2)), ], ) def get_client(request: pytest.FixtureRequest): diff --git a/tests/test_tutorial/test_request_files/test_tutorial001.py b/tests/test_tutorial/test_request_files/test_tutorial001.py index b069199612..a16d951dc6 100644 --- a/tests/test_tutorial/test_request_files/test_tutorial001.py +++ b/tests/test_tutorial/test_request_files/test_tutorial001.py @@ -4,15 +4,12 @@ import pytest from dirty_equals import IsDict from fastapi.testclient import TestClient -from ...utils import needs_py39 - @pytest.fixture( name="client", params=[ - "tutorial001", - "tutorial001_an", - pytest.param("tutorial001_an_py39", marks=needs_py39), + "tutorial001_py39", + "tutorial001_an_py39", ], ) def get_client(request: pytest.FixtureRequest): diff --git a/tests/test_tutorial/test_request_files/test_tutorial001_02.py b/tests/test_tutorial/test_request_files/test_tutorial001_02.py index 9075a17561..caea0d2e8f 100644 --- a/tests/test_tutorial/test_request_files/test_tutorial001_02.py +++ b/tests/test_tutorial/test_request_files/test_tutorial001_02.py @@ -5,16 +5,15 @@ import pytest from dirty_equals import IsDict from fastapi.testclient import TestClient -from ...utils import needs_py39, needs_py310 +from ...utils import needs_py310 @pytest.fixture( name="client", params=[ - "tutorial001_02", + pytest.param("tutorial001_02_py39"), pytest.param("tutorial001_02_py310", marks=needs_py310), - "tutorial001_02_an", - pytest.param("tutorial001_02_an_py39", marks=needs_py39), + pytest.param("tutorial001_02_an_py39"), pytest.param("tutorial001_02_an_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_request_files/test_tutorial001_03.py b/tests/test_tutorial/test_request_files/test_tutorial001_03.py index 9fbe2166c1..53a7a0cf85 100644 --- a/tests/test_tutorial/test_request_files/test_tutorial001_03.py +++ b/tests/test_tutorial/test_request_files/test_tutorial001_03.py @@ -3,15 +3,12 @@ import importlib import pytest from fastapi.testclient import TestClient -from ...utils import needs_py39 - @pytest.fixture( name="client", params=[ - "tutorial001_03", - "tutorial001_03_an", - pytest.param("tutorial001_03_an_py39", marks=needs_py39), + "tutorial001_03_py39", + "tutorial001_03_an_py39", ], ) def get_client(request: pytest.FixtureRequest): diff --git a/tests/test_tutorial/test_request_files/test_tutorial002.py b/tests/test_tutorial/test_request_files/test_tutorial002.py index 446a876578..34dbbb985d 100644 --- a/tests/test_tutorial/test_request_files/test_tutorial002.py +++ b/tests/test_tutorial/test_request_files/test_tutorial002.py @@ -5,16 +5,12 @@ from dirty_equals import IsDict from fastapi import FastAPI from fastapi.testclient import TestClient -from ...utils import needs_py39 - @pytest.fixture( name="app", params=[ - "tutorial002", - "tutorial002_an", - pytest.param("tutorial002_py39", marks=needs_py39), - pytest.param("tutorial002_an_py39", marks=needs_py39), + "tutorial002_py39", + "tutorial002_an_py39", ], ) def get_app(request: pytest.FixtureRequest): diff --git a/tests/test_tutorial/test_request_files/test_tutorial003.py b/tests/test_tutorial/test_request_files/test_tutorial003.py index 8534ba3e9a..fa4bfd5695 100644 --- a/tests/test_tutorial/test_request_files/test_tutorial003.py +++ b/tests/test_tutorial/test_request_files/test_tutorial003.py @@ -4,16 +4,12 @@ import pytest from fastapi import FastAPI from fastapi.testclient import TestClient -from ...utils import needs_py39 - @pytest.fixture( name="app", params=[ - "tutorial003", - "tutorial003_an", - pytest.param("tutorial003_py39", marks=needs_py39), - pytest.param("tutorial003_an_py39", marks=needs_py39), + "tutorial003_py39", + "tutorial003_an_py39", ], ) def get_app(request: pytest.FixtureRequest): diff --git a/tests/test_tutorial/test_request_form_models/test_tutorial001.py b/tests/test_tutorial/test_request_form_models/test_tutorial001.py index 1ca3c96d33..a54df8536c 100644 --- a/tests/test_tutorial/test_request_form_models/test_tutorial001.py +++ b/tests/test_tutorial/test_request_form_models/test_tutorial001.py @@ -4,15 +4,12 @@ import pytest from dirty_equals import IsDict from fastapi.testclient import TestClient -from ...utils import needs_py39 - @pytest.fixture( name="client", params=[ - "tutorial001", - "tutorial001_an", - pytest.param("tutorial001_an_py39", marks=needs_py39), + "tutorial001_py39", + "tutorial001_an_py39", ], ) def get_client(request: pytest.FixtureRequest): diff --git a/tests/test_tutorial/test_request_form_models/test_tutorial002.py b/tests/test_tutorial/test_request_form_models/test_tutorial002.py index b3f6be63ab..9bb90fa064 100644 --- a/tests/test_tutorial/test_request_form_models/test_tutorial002.py +++ b/tests/test_tutorial/test_request_form_models/test_tutorial002.py @@ -3,15 +3,14 @@ import importlib import pytest from fastapi.testclient import TestClient -from ...utils import needs_py39, needs_pydanticv2 +from ...utils import needs_pydanticv2 @pytest.fixture( name="client", params=[ - "tutorial002", - "tutorial002_an", - pytest.param("tutorial002_an_py39", marks=needs_py39), + "tutorial002_py39", + "tutorial002_an_py39", ], ) def get_client(request: pytest.FixtureRequest): diff --git a/tests/test_tutorial/test_request_form_models/test_tutorial002_pv1.py b/tests/test_tutorial/test_request_form_models/test_tutorial002_pv1.py index b503f23a53..41c7833bef 100644 --- a/tests/test_tutorial/test_request_form_models/test_tutorial002_pv1.py +++ b/tests/test_tutorial/test_request_form_models/test_tutorial002_pv1.py @@ -3,15 +3,14 @@ import importlib import pytest from fastapi.testclient import TestClient -from ...utils import needs_py39, needs_pydanticv1 +from ...utils import needs_pydanticv1 @pytest.fixture( name="client", params=[ - "tutorial002_pv1", - "tutorial002_pv1_an", - pytest.param("tutorial002_pv1_an_py39", marks=needs_py39), + "tutorial002_pv1_py39", + "tutorial002_pv1_an_py39", ], ) def get_client(request: pytest.FixtureRequest): diff --git a/tests/test_tutorial/test_request_forms/test_tutorial001.py b/tests/test_tutorial/test_request_forms/test_tutorial001.py index 321f8022b7..da20535cf8 100644 --- a/tests/test_tutorial/test_request_forms/test_tutorial001.py +++ b/tests/test_tutorial/test_request_forms/test_tutorial001.py @@ -4,15 +4,12 @@ import pytest from dirty_equals import IsDict from fastapi.testclient import TestClient -from ...utils import needs_py39 - @pytest.fixture( name="client", params=[ - "tutorial001", - "tutorial001_an", - pytest.param("tutorial001_an_py39", marks=needs_py39), + "tutorial001_py39", + "tutorial001_an_py39", ], ) def get_client(request: pytest.FixtureRequest): diff --git a/tests/test_tutorial/test_request_forms_and_files/test_tutorial001.py b/tests/test_tutorial/test_request_forms_and_files/test_tutorial001.py index d12219245e..f37ffad443 100644 --- a/tests/test_tutorial/test_request_forms_and_files/test_tutorial001.py +++ b/tests/test_tutorial/test_request_forms_and_files/test_tutorial001.py @@ -5,15 +5,12 @@ from dirty_equals import IsDict from fastapi import FastAPI from fastapi.testclient import TestClient -from ...utils import needs_py39 - @pytest.fixture( name="app", params=[ - "tutorial001", - "tutorial001_an", - pytest.param("tutorial001_an_py39", marks=needs_py39), + "tutorial001_py39", + "tutorial001_an_py39", ], ) def get_app(request: pytest.FixtureRequest): diff --git a/tests/test_tutorial/test_response_change_status_code/test_tutorial001.py b/tests/test_tutorial/test_response_change_status_code/test_tutorial001.py index 8ce3dcf1ab..05d5ca619f 100644 --- a/tests/test_tutorial/test_response_change_status_code/test_tutorial001.py +++ b/tests/test_tutorial/test_response_change_status_code/test_tutorial001.py @@ -1,6 +1,6 @@ from fastapi.testclient import TestClient -from docs_src.response_change_status_code.tutorial001 import app +from docs_src.response_change_status_code.tutorial001_py39 import app client = TestClient(app) diff --git a/tests/test_tutorial/test_response_cookies/test_tutorial001.py b/tests/test_tutorial/test_response_cookies/test_tutorial001.py index eecd1a24c9..6b931c8bda 100644 --- a/tests/test_tutorial/test_response_cookies/test_tutorial001.py +++ b/tests/test_tutorial/test_response_cookies/test_tutorial001.py @@ -1,6 +1,6 @@ from fastapi.testclient import TestClient -from docs_src.response_cookies.tutorial001 import app +from docs_src.response_cookies.tutorial001_py39 import app client = TestClient(app) diff --git a/tests/test_tutorial/test_response_cookies/test_tutorial002.py b/tests/test_tutorial/test_response_cookies/test_tutorial002.py index 3e390025fa..3ee5f500c5 100644 --- a/tests/test_tutorial/test_response_cookies/test_tutorial002.py +++ b/tests/test_tutorial/test_response_cookies/test_tutorial002.py @@ -1,6 +1,6 @@ from fastapi.testclient import TestClient -from docs_src.response_cookies.tutorial002 import app +from docs_src.response_cookies.tutorial002_py39 import app client = TestClient(app) diff --git a/tests/test_tutorial/test_response_directly/test_tutorial001.py b/tests/test_tutorial/test_response_directly/test_tutorial001.py index 2cc4f3b0c1..127f0e4c1d 100644 --- a/tests/test_tutorial/test_response_directly/test_tutorial001.py +++ b/tests/test_tutorial/test_response_directly/test_tutorial001.py @@ -9,7 +9,7 @@ from ...utils import needs_py310, needs_pydanticv1, needs_pydanticv2 @pytest.fixture( name="client", params=[ - pytest.param("tutorial001"), + pytest.param("tutorial001_py39"), pytest.param("tutorial001_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_response_headers/test_tutorial001.py b/tests/test_tutorial/test_response_headers/test_tutorial001.py index 1549d6b5b1..6232aad23e 100644 --- a/tests/test_tutorial/test_response_headers/test_tutorial001.py +++ b/tests/test_tutorial/test_response_headers/test_tutorial001.py @@ -1,6 +1,6 @@ from fastapi.testclient import TestClient -from docs_src.response_headers.tutorial001 import app +from docs_src.response_headers.tutorial001_py39 import app client = TestClient(app) diff --git a/tests/test_tutorial/test_response_headers/test_tutorial002.py b/tests/test_tutorial/test_response_headers/test_tutorial002.py index 2826833f84..2ac2226cb1 100644 --- a/tests/test_tutorial/test_response_headers/test_tutorial002.py +++ b/tests/test_tutorial/test_response_headers/test_tutorial002.py @@ -1,6 +1,6 @@ from fastapi.testclient import TestClient -from docs_src.response_headers.tutorial002 import app +from docs_src.response_headers.tutorial002_py39 import app client = TestClient(app) diff --git a/tests/test_tutorial/test_response_model/test_tutorial003.py b/tests/test_tutorial/test_response_model/test_tutorial003.py index 70cfd6e4cc..0f9eac890b 100644 --- a/tests/test_tutorial/test_response_model/test_tutorial003.py +++ b/tests/test_tutorial/test_response_model/test_tutorial003.py @@ -10,7 +10,7 @@ from ...utils import needs_py310 @pytest.fixture( name="client", params=[ - "tutorial003", + pytest.param("tutorial003_py39"), pytest.param("tutorial003_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_response_model/test_tutorial003_01.py b/tests/test_tutorial/test_response_model/test_tutorial003_01.py index 3975856b6c..1a7ce4c7a1 100644 --- a/tests/test_tutorial/test_response_model/test_tutorial003_01.py +++ b/tests/test_tutorial/test_response_model/test_tutorial003_01.py @@ -10,7 +10,7 @@ from ...utils import needs_py310 @pytest.fixture( name="client", params=[ - "tutorial003_01", + pytest.param("tutorial003_01_py39"), pytest.param("tutorial003_01_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_response_model/test_tutorial003_02.py b/tests/test_tutorial/test_response_model/test_tutorial003_02.py index eabd203456..b7507b7110 100644 --- a/tests/test_tutorial/test_response_model/test_tutorial003_02.py +++ b/tests/test_tutorial/test_response_model/test_tutorial003_02.py @@ -1,6 +1,6 @@ from fastapi.testclient import TestClient -from docs_src.response_model.tutorial003_02 import app +from docs_src.response_model.tutorial003_02_py39 import app client = TestClient(app) diff --git a/tests/test_tutorial/test_response_model/test_tutorial003_03.py b/tests/test_tutorial/test_response_model/test_tutorial003_03.py index 970ff58450..ea3c733b24 100644 --- a/tests/test_tutorial/test_response_model/test_tutorial003_03.py +++ b/tests/test_tutorial/test_response_model/test_tutorial003_03.py @@ -1,6 +1,6 @@ from fastapi.testclient import TestClient -from docs_src.response_model.tutorial003_03 import app +from docs_src.response_model.tutorial003_03_py39 import app client = TestClient(app) diff --git a/tests/test_tutorial/test_response_model/test_tutorial003_04.py b/tests/test_tutorial/test_response_model/test_tutorial003_04.py index f32e93ddcb..145af126fd 100644 --- a/tests/test_tutorial/test_response_model/test_tutorial003_04.py +++ b/tests/test_tutorial/test_response_model/test_tutorial003_04.py @@ -9,7 +9,7 @@ from ...utils import needs_py310 @pytest.mark.parametrize( "module_name", [ - "tutorial003_04", + pytest.param("tutorial003_04_py39"), pytest.param("tutorial003_04_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_response_model/test_tutorial003_05.py b/tests/test_tutorial/test_response_model/test_tutorial003_05.py index 9500852e15..19a7c601bb 100644 --- a/tests/test_tutorial/test_response_model/test_tutorial003_05.py +++ b/tests/test_tutorial/test_response_model/test_tutorial003_05.py @@ -9,7 +9,7 @@ from ...utils import needs_py310 @pytest.fixture( name="client", params=[ - "tutorial003_05", + pytest.param("tutorial003_05_py39"), pytest.param("tutorial003_05_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_response_model/test_tutorial004.py b/tests/test_tutorial/test_response_model/test_tutorial004.py index 449a52b813..19f6998f70 100644 --- a/tests/test_tutorial/test_response_model/test_tutorial004.py +++ b/tests/test_tutorial/test_response_model/test_tutorial004.py @@ -4,14 +4,13 @@ import pytest from dirty_equals import IsDict, IsOneOf from fastapi.testclient import TestClient -from ...utils import needs_py39, needs_py310 +from ...utils import needs_py310 @pytest.fixture( name="client", params=[ - "tutorial004", - pytest.param("tutorial004_py39", marks=needs_py39), + pytest.param("tutorial004_py39"), pytest.param("tutorial004_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_response_model/test_tutorial005.py b/tests/test_tutorial/test_response_model/test_tutorial005.py index a633a3fddd..47d77dc498 100644 --- a/tests/test_tutorial/test_response_model/test_tutorial005.py +++ b/tests/test_tutorial/test_response_model/test_tutorial005.py @@ -10,7 +10,7 @@ from ...utils import needs_py310 @pytest.fixture( name="client", params=[ - "tutorial005", + pytest.param("tutorial005_py39"), pytest.param("tutorial005_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_response_model/test_tutorial006.py b/tests/test_tutorial/test_response_model/test_tutorial006.py index 863522d1b4..a03aa41e8c 100644 --- a/tests/test_tutorial/test_response_model/test_tutorial006.py +++ b/tests/test_tutorial/test_response_model/test_tutorial006.py @@ -10,7 +10,7 @@ from ...utils import needs_py310 @pytest.fixture( name="client", params=[ - "tutorial006", + pytest.param("tutorial006_py39"), pytest.param("tutorial006_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_schema_extra_example/test_tutorial001.py b/tests/test_tutorial/test_schema_extra_example/test_tutorial001.py index c21cbb4bc2..4d1808cf6a 100644 --- a/tests/test_tutorial/test_schema_extra_example/test_tutorial001.py +++ b/tests/test_tutorial/test_schema_extra_example/test_tutorial001.py @@ -9,7 +9,7 @@ from ...utils import needs_py310, needs_pydanticv2 @pytest.fixture( name="client", params=[ - "tutorial001", + pytest.param("tutorial001_py39"), pytest.param("tutorial001_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_schema_extra_example/test_tutorial001_pv1.py b/tests/test_tutorial/test_schema_extra_example/test_tutorial001_pv1.py index b79f42e642..552bb66970 100644 --- a/tests/test_tutorial/test_schema_extra_example/test_tutorial001_pv1.py +++ b/tests/test_tutorial/test_schema_extra_example/test_tutorial001_pv1.py @@ -9,7 +9,7 @@ from ...utils import needs_py310, needs_pydanticv1 @pytest.fixture( name="client", params=[ - "tutorial001_pv1", + pytest.param("tutorial001_pv1_py39"), pytest.param("tutorial001_pv1_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_schema_extra_example/test_tutorial004.py b/tests/test_tutorial/test_schema_extra_example/test_tutorial004.py index 61aefd12a8..47ecb9ba73 100644 --- a/tests/test_tutorial/test_schema_extra_example/test_tutorial004.py +++ b/tests/test_tutorial/test_schema_extra_example/test_tutorial004.py @@ -4,16 +4,15 @@ import pytest from dirty_equals import IsDict from fastapi.testclient import TestClient -from ...utils import needs_py39, needs_py310 +from ...utils import needs_py310 @pytest.fixture( name="client", params=[ - "tutorial004", + pytest.param("tutorial004_py39"), pytest.param("tutorial004_py310", marks=needs_py310), - "tutorial004_an", - pytest.param("tutorial004_an_py39", marks=needs_py39), + pytest.param("tutorial004_an_py39"), pytest.param("tutorial004_an_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_schema_extra_example/test_tutorial005.py b/tests/test_tutorial/test_schema_extra_example/test_tutorial005.py index 12859227b1..1c964f3d15 100644 --- a/tests/test_tutorial/test_schema_extra_example/test_tutorial005.py +++ b/tests/test_tutorial/test_schema_extra_example/test_tutorial005.py @@ -4,16 +4,15 @@ import pytest from dirty_equals import IsDict from fastapi.testclient import TestClient -from ...utils import needs_py39, needs_py310 +from ...utils import needs_py310 @pytest.fixture( name="client", params=[ - "tutorial005", + pytest.param("tutorial005_py39"), pytest.param("tutorial005_py310", marks=needs_py310), - "tutorial005_an", - pytest.param("tutorial005_an_py39", marks=needs_py39), + pytest.param("tutorial005_an_py39"), pytest.param("tutorial005_an_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_security/test_tutorial001.py b/tests/test_tutorial/test_security/test_tutorial001.py index f572d6e3e1..cdaa50b191 100644 --- a/tests/test_tutorial/test_security/test_tutorial001.py +++ b/tests/test_tutorial/test_security/test_tutorial001.py @@ -3,15 +3,12 @@ import importlib import pytest from fastapi.testclient import TestClient -from ...utils import needs_py39 - @pytest.fixture( name="client", params=[ - "tutorial001", - "tutorial001_an", - pytest.param("tutorial001_an_py39", marks=needs_py39), + pytest.param("tutorial001_py39"), + pytest.param("tutorial001_an_py39"), ], ) def get_client(request: pytest.FixtureRequest): diff --git a/tests/test_tutorial/test_security/test_tutorial003.py b/tests/test_tutorial/test_security/test_tutorial003.py index 6b87351139..000c8b2ac4 100644 --- a/tests/test_tutorial/test_security/test_tutorial003.py +++ b/tests/test_tutorial/test_security/test_tutorial003.py @@ -4,16 +4,15 @@ import pytest from dirty_equals import IsDict from fastapi.testclient import TestClient -from ...utils import needs_py39, needs_py310 +from ...utils import needs_py310 @pytest.fixture( name="client", params=[ - "tutorial003", + pytest.param("tutorial003_py39"), pytest.param("tutorial003_py310", marks=needs_py310), - "tutorial003_an", - pytest.param("tutorial003_an_py39", marks=needs_py39), + pytest.param("tutorial003_an_py39"), pytest.param("tutorial003_an_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_security/test_tutorial005.py b/tests/test_tutorial/test_security/test_tutorial005.py index ad644d61bb..7953e8e3f6 100644 --- a/tests/test_tutorial/test_security/test_tutorial005.py +++ b/tests/test_tutorial/test_security/test_tutorial005.py @@ -5,17 +5,15 @@ import pytest from dirty_equals import IsDict, IsOneOf from fastapi.testclient import TestClient -from ...utils import needs_py39, needs_py310 +from ...utils import needs_py310 @pytest.fixture( name="mod", params=[ - "tutorial005", + pytest.param("tutorial005_py39"), pytest.param("tutorial005_py310", marks=needs_py310), - "tutorial005_an", - pytest.param("tutorial005_py39", marks=needs_py39), - pytest.param("tutorial005_an_py39", marks=needs_py39), + pytest.param("tutorial005_an_py39"), pytest.param("tutorial005_an_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_security/test_tutorial006.py b/tests/test_tutorial/test_security/test_tutorial006.py index 9587159dc2..a4b3104bbc 100644 --- a/tests/test_tutorial/test_security/test_tutorial006.py +++ b/tests/test_tutorial/test_security/test_tutorial006.py @@ -4,15 +4,12 @@ from base64 import b64encode import pytest from fastapi.testclient import TestClient -from ...utils import needs_py39 - @pytest.fixture( name="client", params=[ - "tutorial006", - "tutorial006_an", - pytest.param("tutorial006_an_py39", marks=needs_py39), + pytest.param("tutorial006_py39"), + pytest.param("tutorial006_an_py39"), ], ) def get_client(request: pytest.FixtureRequest): diff --git a/tests/test_tutorial/test_separate_openapi_schemas/test_tutorial001.py b/tests/test_tutorial/test_separate_openapi_schemas/test_tutorial001.py index 059fb889b3..b59d799a31 100644 --- a/tests/test_tutorial/test_separate_openapi_schemas/test_tutorial001.py +++ b/tests/test_tutorial/test_separate_openapi_schemas/test_tutorial001.py @@ -3,15 +3,14 @@ import importlib import pytest from fastapi.testclient import TestClient -from ...utils import needs_py39, needs_py310, needs_pydanticv2 +from ...utils import needs_py310, needs_pydanticv2 @pytest.fixture( name="client", params=[ - "tutorial001", + pytest.param("tutorial001_py39"), pytest.param("tutorial001_py310", marks=needs_py310), - pytest.param("tutorial001_py39", marks=needs_py39), ], ) def get_client(request: pytest.FixtureRequest) -> TestClient: diff --git a/tests/test_tutorial/test_separate_openapi_schemas/test_tutorial002.py b/tests/test_tutorial/test_separate_openapi_schemas/test_tutorial002.py index cc9afeab75..61fbacfc34 100644 --- a/tests/test_tutorial/test_separate_openapi_schemas/test_tutorial002.py +++ b/tests/test_tutorial/test_separate_openapi_schemas/test_tutorial002.py @@ -3,15 +3,14 @@ import importlib import pytest from fastapi.testclient import TestClient -from ...utils import needs_py39, needs_py310, needs_pydanticv2 +from ...utils import needs_py310, needs_pydanticv2 @pytest.fixture( name="client", params=[ - "tutorial002", + pytest.param("tutorial002_py39"), pytest.param("tutorial002_py310", marks=needs_py310), - pytest.param("tutorial002_py39", marks=needs_py39), ], ) def get_client(request: pytest.FixtureRequest) -> TestClient: diff --git a/tests/test_tutorial/test_settings/test_app02.py b/tests/test_tutorial/test_settings/test_app02.py index 5e1232ea01..9cedc5a526 100644 --- a/tests/test_tutorial/test_settings/test_app02.py +++ b/tests/test_tutorial/test_settings/test_app02.py @@ -4,15 +4,14 @@ from types import ModuleType import pytest from pytest import MonkeyPatch -from ...utils import needs_py39, needs_pydanticv2 +from ...utils import needs_pydanticv2 @pytest.fixture( name="mod_path", params=[ - pytest.param("app02"), - pytest.param("app02_an"), - pytest.param("app02_an_py39", marks=needs_py39), + pytest.param("app02_py39"), + pytest.param("app02_an_py39"), ], ) def get_mod_path(request: pytest.FixtureRequest): diff --git a/tests/test_tutorial/test_settings/test_app03.py b/tests/test_tutorial/test_settings/test_app03.py index d9872c15f2..dbaf8f3f90 100644 --- a/tests/test_tutorial/test_settings/test_app03.py +++ b/tests/test_tutorial/test_settings/test_app03.py @@ -5,15 +5,14 @@ import pytest from fastapi.testclient import TestClient from pytest import MonkeyPatch -from ...utils import needs_py39, needs_pydanticv1, needs_pydanticv2 +from ...utils import needs_pydanticv1, needs_pydanticv2 @pytest.fixture( name="mod_path", params=[ - pytest.param("app03"), - pytest.param("app03_an"), - pytest.param("app03_an_py39", marks=needs_py39), + pytest.param("app03_py39"), + pytest.param("app03_an_py39"), ], ) def get_mod_path(request: pytest.FixtureRequest): diff --git a/tests/test_tutorial/test_settings/test_tutorial001.py b/tests/test_tutorial/test_settings/test_tutorial001.py index 92a5782d4d..2c6dce261f 100644 --- a/tests/test_tutorial/test_settings/test_tutorial001.py +++ b/tests/test_tutorial/test_settings/test_tutorial001.py @@ -10,8 +10,8 @@ from ...utils import needs_pydanticv1, needs_pydanticv2 @pytest.fixture( name="app", params=[ - pytest.param("tutorial001", marks=needs_pydanticv2), - pytest.param("tutorial001_pv1", marks=needs_pydanticv1), + pytest.param("tutorial001_py39", marks=needs_pydanticv2), + pytest.param("tutorial001_pv1_py39", marks=needs_pydanticv1), ], ) def get_app(request: pytest.FixtureRequest, monkeypatch: MonkeyPatch): diff --git a/tests/test_tutorial/test_sql_databases/test_tutorial001.py b/tests/test_tutorial/test_sql_databases/test_tutorial001.py index b45be4884d..e3e6bac128 100644 --- a/tests/test_tutorial/test_sql_databases/test_tutorial001.py +++ b/tests/test_tutorial/test_sql_databases/test_tutorial001.py @@ -9,7 +9,7 @@ from sqlalchemy import StaticPool from sqlmodel import SQLModel, create_engine from sqlmodel.main import default_registry -from tests.utils import needs_py39, needs_py310 +from tests.utils import needs_py310 def clear_sqlmodel(): @@ -22,11 +22,9 @@ def clear_sqlmodel(): @pytest.fixture( name="client", params=[ - "tutorial001", - pytest.param("tutorial001_py39", marks=needs_py39), + pytest.param("tutorial001_py39"), pytest.param("tutorial001_py310", marks=needs_py310), - "tutorial001_an", - pytest.param("tutorial001_an_py39", marks=needs_py39), + pytest.param("tutorial001_an_py39"), pytest.param("tutorial001_an_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_sql_databases/test_tutorial002.py b/tests/test_tutorial/test_sql_databases/test_tutorial002.py index da0b8b7ce7..e3b8c7f9e4 100644 --- a/tests/test_tutorial/test_sql_databases/test_tutorial002.py +++ b/tests/test_tutorial/test_sql_databases/test_tutorial002.py @@ -9,7 +9,7 @@ from sqlalchemy import StaticPool from sqlmodel import SQLModel, create_engine from sqlmodel.main import default_registry -from tests.utils import needs_py39, needs_py310 +from tests.utils import needs_py310 def clear_sqlmodel(): @@ -22,11 +22,9 @@ def clear_sqlmodel(): @pytest.fixture( name="client", params=[ - "tutorial002", - pytest.param("tutorial002_py39", marks=needs_py39), + pytest.param("tutorial002_py39"), pytest.param("tutorial002_py310", marks=needs_py310), - "tutorial002_an", - pytest.param("tutorial002_an_py39", marks=needs_py39), + pytest.param("tutorial002_an_py39"), pytest.param("tutorial002_an_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_sub_applications/test_tutorial001.py b/tests/test_tutorial/test_sub_applications/test_tutorial001.py index 0790d207be..ef1f80164b 100644 --- a/tests/test_tutorial/test_sub_applications/test_tutorial001.py +++ b/tests/test_tutorial/test_sub_applications/test_tutorial001.py @@ -1,6 +1,6 @@ from fastapi.testclient import TestClient -from docs_src.sub_applications.tutorial001 import app +from docs_src.sub_applications.tutorial001_py39 import app client = TestClient(app) diff --git a/tests/test_tutorial/test_templates/test_tutorial001.py b/tests/test_tutorial/test_templates/test_tutorial001.py index 4d4729425e..818508037d 100644 --- a/tests/test_tutorial/test_templates/test_tutorial001.py +++ b/tests/test_tutorial/test_templates/test_tutorial001.py @@ -11,7 +11,7 @@ def test_main(): shutil.rmtree("./templates") shutil.copytree("./docs_src/templates/templates/", "./templates") shutil.copytree("./docs_src/templates/static/", "./static") - from docs_src.templates.tutorial001 import app + from docs_src.templates.tutorial001_py39 import app client = TestClient(app) response = client.get("/items/foo") diff --git a/tests/test_tutorial/test_testing/test_main.py b/tests/test_tutorial/test_testing/test_main_a.py similarity index 90% rename from tests/test_tutorial/test_testing/test_main.py rename to tests/test_tutorial/test_testing/test_main_a.py index fe34980813..9b3c796bdc 100644 --- a/tests/test_tutorial/test_testing/test_main.py +++ b/tests/test_tutorial/test_testing/test_main_a.py @@ -1,4 +1,4 @@ -from docs_src.app_testing.test_main import client, test_read_main +from docs_src.app_testing.app_a_py39.test_main import client, test_read_main def test_main(): diff --git a/tests/test_tutorial/test_testing/test_main_b.py b/tests/test_tutorial/test_testing/test_main_b.py index aa7f969c6d..3d679cd5a6 100644 --- a/tests/test_tutorial/test_testing/test_main_b.py +++ b/tests/test_tutorial/test_testing/test_main_b.py @@ -3,16 +3,15 @@ from types import ModuleType import pytest -from ...utils import needs_py39, needs_py310 +from ...utils import needs_py310 @pytest.fixture( name="test_module", params=[ - "app_b.test_main", + "app_b_py39.test_main", pytest.param("app_b_py310.test_main", marks=needs_py310), - "app_b_an.test_main", - pytest.param("app_b_an_py39.test_main", marks=needs_py39), + "app_b_an_py39.test_main", pytest.param("app_b_an_py310.test_main", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_testing/test_tutorial001.py b/tests/test_tutorial/test_testing/test_tutorial001.py index 471e896c93..5f6533306e 100644 --- a/tests/test_tutorial/test_testing/test_tutorial001.py +++ b/tests/test_tutorial/test_testing/test_tutorial001.py @@ -1,4 +1,4 @@ -from docs_src.app_testing.tutorial001 import client, test_read_main +from docs_src.app_testing.tutorial001_py39 import client, test_read_main def test_main(): diff --git a/tests/test_tutorial/test_testing/test_tutorial002.py b/tests/test_tutorial/test_testing/test_tutorial002.py index ec4f91ee7f..cc9b5ba27c 100644 --- a/tests/test_tutorial/test_testing/test_tutorial002.py +++ b/tests/test_tutorial/test_testing/test_tutorial002.py @@ -1,4 +1,4 @@ -from docs_src.app_testing.tutorial002 import test_read_main, test_websocket +from docs_src.app_testing.tutorial002_py39 import test_read_main, test_websocket def test_main(): diff --git a/tests/test_tutorial/test_testing/test_tutorial003.py b/tests/test_tutorial/test_testing/test_tutorial003.py index 2a5d670712..4faa820e98 100644 --- a/tests/test_tutorial/test_testing/test_tutorial003.py +++ b/tests/test_tutorial/test_testing/test_tutorial003.py @@ -3,5 +3,5 @@ import pytest def test_main(): with pytest.warns(DeprecationWarning): - from docs_src.app_testing.tutorial003 import test_read_items + from docs_src.app_testing.tutorial003_py39 import test_read_items test_read_items() diff --git a/tests/test_tutorial/test_testing/test_tutorial004.py b/tests/test_tutorial/test_testing/test_tutorial004.py index 812ee44c1f..c95214ffe3 100644 --- a/tests/test_tutorial/test_testing/test_tutorial004.py +++ b/tests/test_tutorial/test_testing/test_tutorial004.py @@ -1,4 +1,4 @@ -from docs_src.app_testing.tutorial004 import test_read_items +from docs_src.app_testing.tutorial004_py39 import test_read_items def test_main(): diff --git a/tests/test_tutorial/test_testing_dependencies/test_tutorial001.py b/tests/test_tutorial/test_testing_dependencies/test_tutorial001.py index 00ee6ab1ea..6e9656bf55 100644 --- a/tests/test_tutorial/test_testing_dependencies/test_tutorial001.py +++ b/tests/test_tutorial/test_testing_dependencies/test_tutorial001.py @@ -3,16 +3,15 @@ from types import ModuleType import pytest -from ...utils import needs_py39, needs_py310 +from ...utils import needs_py310 @pytest.fixture( name="test_module", params=[ - "tutorial001", + pytest.param("tutorial001_py39"), pytest.param("tutorial001_py310", marks=needs_py310), - "tutorial001_an", - pytest.param("tutorial001_an_py39", marks=needs_py39), + pytest.param("tutorial001_an_py39"), pytest.param("tutorial001_an_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_using_request_directly/test_tutorial001.py b/tests/test_tutorial/test_using_request_directly/test_tutorial001.py index 54c53ae1e3..33e661b164 100644 --- a/tests/test_tutorial/test_using_request_directly/test_tutorial001.py +++ b/tests/test_tutorial/test_using_request_directly/test_tutorial001.py @@ -1,6 +1,6 @@ from fastapi.testclient import TestClient -from docs_src.using_request_directly.tutorial001 import app +from docs_src.using_request_directly.tutorial001_py39 import app client = TestClient(app) diff --git a/tests/test_tutorial/test_websockets/test_tutorial001.py b/tests/test_tutorial/test_websockets/test_tutorial001.py index 7dbecb2650..4f8368db28 100644 --- a/tests/test_tutorial/test_websockets/test_tutorial001.py +++ b/tests/test_tutorial/test_websockets/test_tutorial001.py @@ -2,7 +2,7 @@ import pytest from fastapi.testclient import TestClient from fastapi.websockets import WebSocketDisconnect -from docs_src.websockets.tutorial001 import app +from docs_src.websockets.tutorial001_py39 import app client = TestClient(app) diff --git a/tests/test_tutorial/test_websockets/test_tutorial002.py b/tests/test_tutorial/test_websockets/test_tutorial002.py index 51aa5752a6..ebf1fc8e81 100644 --- a/tests/test_tutorial/test_websockets/test_tutorial002.py +++ b/tests/test_tutorial/test_websockets/test_tutorial002.py @@ -5,16 +5,15 @@ from fastapi import FastAPI from fastapi.testclient import TestClient from fastapi.websockets import WebSocketDisconnect -from ...utils import needs_py39, needs_py310 +from ...utils import needs_py310 @pytest.fixture( name="app", params=[ - "tutorial002", + pytest.param("tutorial002_py39"), pytest.param("tutorial002_py310", marks=needs_py310), - "tutorial002_an", - pytest.param("tutorial002_an_py39", marks=needs_py39), + pytest.param("tutorial002_an_py39"), pytest.param("tutorial002_an_py310", marks=needs_py310), ], ) diff --git a/tests/test_tutorial/test_websockets/test_tutorial003.py b/tests/test_tutorial/test_websockets/test_tutorial003.py index 85efc18590..0be1fc81d6 100644 --- a/tests/test_tutorial/test_websockets/test_tutorial003.py +++ b/tests/test_tutorial/test_websockets/test_tutorial003.py @@ -4,14 +4,11 @@ from types import ModuleType import pytest from fastapi.testclient import TestClient -from ...utils import needs_py39 - @pytest.fixture( name="mod", params=[ - pytest.param("tutorial003"), - pytest.param("tutorial003_py39", marks=needs_py39), + pytest.param("tutorial003_py39"), ], ) def get_mod(request: pytest.FixtureRequest): @@ -32,17 +29,16 @@ def get_client(mod: ModuleType): return client -@needs_py39 def test_get(client: TestClient, html: str): response = client.get("/") assert response.text == html -@needs_py39 def test_websocket_handle_disconnection(client: TestClient): - with client.websocket_connect("/ws/1234") as connection, client.websocket_connect( - "/ws/5678" - ) as connection_two: + with ( + client.websocket_connect("/ws/1234") as connection, + client.websocket_connect("/ws/5678") as connection_two, + ): connection.send_text("Hello from 1234") data1 = connection.receive_text() assert data1 == "You wrote: Hello from 1234" diff --git a/tests/test_tutorial/test_wsgi/test_tutorial001.py b/tests/test_tutorial/test_wsgi/test_tutorial001.py index 4f82252739..9fe8c2a4b8 100644 --- a/tests/test_tutorial/test_wsgi/test_tutorial001.py +++ b/tests/test_tutorial/test_wsgi/test_tutorial001.py @@ -1,6 +1,6 @@ from fastapi.testclient import TestClient -from docs_src.wsgi.tutorial001 import app +from docs_src.wsgi.tutorial001_py39 import app client = TestClient(app) diff --git a/tests/test_union_body_discriminator.py b/tests/test_union_body_discriminator.py index 6af9e1d226..bf41a72915 100644 --- a/tests/test_union_body_discriminator.py +++ b/tests/test_union_body_discriminator.py @@ -1,11 +1,11 @@ -from typing import Any, Dict, Union +from typing import Annotated, Any, Union from dirty_equals import IsDict from fastapi import FastAPI from fastapi.testclient import TestClient from inline_snapshot import snapshot from pydantic import BaseModel, Field -from typing_extensions import Annotated, Literal +from typing_extensions import Literal from .utils import needs_pydanticv2 @@ -32,7 +32,7 @@ def test_discriminator_pydantic_v2() -> None: @app.post("/items/") def save_union_body_discriminator( item: Item, q: Annotated[str, Field(description="Query string")] - ) -> Dict[str, Any]: + ) -> dict[str, Any]: return {"item": item} client = TestClient(app) diff --git a/tests/test_union_body_discriminator_annotated.py b/tests/test_union_body_discriminator_annotated.py index 14145e6f60..f8108c8df4 100644 --- a/tests/test_union_body_discriminator_annotated.py +++ b/tests/test_union_body_discriminator_annotated.py @@ -1,13 +1,12 @@ # Ref: https://github.com/fastapi/fastapi/discussions/14495 -from typing import Union +from typing import Annotated, Union import pytest from fastapi import FastAPI from fastapi.testclient import TestClient from inline_snapshot import snapshot from pydantic import BaseModel -from typing_extensions import Annotated from .utils import needs_pydanticv2 diff --git a/tests/test_union_forms.py b/tests/test_union_forms.py index cbe98ea825..018949f0c7 100644 --- a/tests/test_union_forms.py +++ b/tests/test_union_forms.py @@ -1,9 +1,8 @@ -from typing import Union +from typing import Annotated, Union from fastapi import FastAPI, Form from fastapi.testclient import TestClient from pydantic import BaseModel -from typing_extensions import Annotated app = FastAPI() diff --git a/tests/test_validate_response.py b/tests/test_validate_response.py index cd97007a44..938d419566 100644 --- a/tests/test_validate_response.py +++ b/tests/test_validate_response.py @@ -1,4 +1,4 @@ -from typing import List, Optional, Union +from typing import Optional, Union import pytest from fastapi import FastAPI @@ -12,7 +12,7 @@ app = FastAPI() class Item(BaseModel): name: str price: Optional[float] = None - owner_ids: Optional[List[int]] = None + owner_ids: Optional[list[int]] = None @app.get("/items/invalid", response_model=Item) @@ -38,7 +38,7 @@ def get_innerinvalid(): return {"name": "double invalid", "price": "foo", "owner_ids": ["foo", "bar"]} -@app.get("/items/invalidlist", response_model=List[Item]) +@app.get("/items/invalidlist", response_model=list[Item]) def get_invalidlist(): return [ {"name": "foo"}, diff --git a/tests/test_validate_response_dataclass.py b/tests/test_validate_response_dataclass.py index 0415988a0b..67282bcde1 100644 --- a/tests/test_validate_response_dataclass.py +++ b/tests/test_validate_response_dataclass.py @@ -1,4 +1,4 @@ -from typing import List, Optional +from typing import Optional import pytest from fastapi import FastAPI @@ -13,7 +13,7 @@ app = FastAPI() class Item: name: str price: Optional[float] = None - owner_ids: Optional[List[int]] = None + owner_ids: Optional[list[int]] = None @app.get("/items/invalid", response_model=Item) @@ -26,7 +26,7 @@ def get_innerinvalid(): return {"name": "double invalid", "price": "foo", "owner_ids": ["foo", "bar"]} -@app.get("/items/invalidlist", response_model=List[Item]) +@app.get("/items/invalidlist", response_model=list[Item]) def get_invalidlist(): return [ {"name": "foo"}, diff --git a/tests/test_validate_response_recursive/app.py b/tests/test_validate_response_recursive/app.py index d23d279808..8f76572ba6 100644 --- a/tests/test_validate_response_recursive/app.py +++ b/tests/test_validate_response_recursive/app.py @@ -1,5 +1,3 @@ -from typing import List - from fastapi import FastAPI from fastapi._compat import PYDANTIC_V2 from pydantic import BaseModel @@ -8,17 +6,17 @@ app = FastAPI() class RecursiveItem(BaseModel): - sub_items: List["RecursiveItem"] = [] + sub_items: list["RecursiveItem"] = [] name: str class RecursiveSubitemInSubmodel(BaseModel): - sub_items2: List["RecursiveItemViaSubmodel"] = [] + sub_items2: list["RecursiveItemViaSubmodel"] = [] name: str class RecursiveItemViaSubmodel(BaseModel): - sub_items1: List[RecursiveSubitemInSubmodel] = [] + sub_items1: list[RecursiveSubitemInSubmodel] = [] name: str diff --git a/tests/test_webhooks_security.py b/tests/test_webhooks_security.py index 21a694cb54..982ae1e21d 100644 --- a/tests/test_webhooks_security.py +++ b/tests/test_webhooks_security.py @@ -1,10 +1,10 @@ from datetime import datetime +from typing import Annotated from fastapi import FastAPI, Security from fastapi.security import HTTPBearer from fastapi.testclient import TestClient from pydantic import BaseModel -from typing_extensions import Annotated app = FastAPI() diff --git a/tests/test_ws_dependencies.py b/tests/test_ws_dependencies.py index ccb1c4b7da..51b982c00e 100644 --- a/tests/test_ws_dependencies.py +++ b/tests/test_ws_dependencies.py @@ -1,16 +1,15 @@ import json -from typing import List +from typing import Annotated from fastapi import APIRouter, Depends, FastAPI, WebSocket from fastapi.testclient import TestClient -from typing_extensions import Annotated -def dependency_list() -> List[str]: +def dependency_list() -> list[str]: return [] -DepList = Annotated[List[str], Depends(dependency_list)] +DepList = Annotated[list[str], Depends(dependency_list)] def create_dependency(name: str):