diff --git a/docs/de/docs/advanced/advanced-dependencies.md b/docs/de/docs/advanced/advanced-dependencies.md index da5f28c7c..2254dcf53 100644 --- a/docs/de/docs/advanced/advanced-dependencies.md +++ b/docs/de/docs/advanced/advanced-dependencies.md @@ -70,12 +70,22 @@ Wenn Sie das hier alles verstanden haben, wissen Sie bereits, wie diese Sicherhe Sie benötigen diese technischen Details höchstwahrscheinlich nicht. -Diese Details sind hauptsächlich nützlich, wenn Sie eine FastAPI-Anwendung haben, die älter als 0.118.0 ist, und Sie auf Probleme mit Abhängigkeiten mit `yield` stoßen. +Diese Details sind hauptsächlich nützlich, wenn Sie eine FastAPI-Anwendung haben, die älter als 0.121.0 ist, und Sie auf Probleme mit Abhängigkeiten mit `yield` stoßen. /// Abhängigkeiten mit `yield` haben sich im Laufe der Zeit weiterentwickelt, um verschiedene Anwendungsfälle abzudecken und einige Probleme zu beheben, hier ist eine Zusammenfassung der Änderungen. +### Abhängigkeiten mit `yield` und `scope` { #dependencies-with-yield-and-scope } + +In Version 0.121.0 hat FastAPI Unterstützung für `Depends(scope="function")` für Abhängigkeiten mit `yield` hinzugefügt. + +Mit `Depends(scope="function")` wird der Exit-Code nach `yield` direkt nach dem Ende der *Pfadoperation-Funktion* ausgeführt, bevor die Response an den Client gesendet wird. + +Und bei Verwendung von `Depends(scope="request")` (dem Default) wird der Exit-Code nach `yield` ausgeführt, nachdem die Response gesendet wurde. + +Mehr dazu finden Sie in der Dokumentation zu [Abhängigkeiten mit `yield` – Frühes Beenden und `scope`](../tutorial/dependencies/dependencies-with-yield.md#early-exit-and-scope). + ### Abhängigkeiten mit `yield` und `StreamingResponse`, Technische Details { #dependencies-with-yield-and-streamingresponse-technical-details } Vor FastAPI 0.118.0 wurde bei Verwendung einer Abhängigkeit mit `yield` der Exit-Code nach der *Pfadoperation-Funktion* ausgeführt, aber unmittelbar bevor die Response gesendet wurde. diff --git a/docs/de/docs/tutorial/dependencies/dependencies-with-yield.md b/docs/de/docs/tutorial/dependencies/dependencies-with-yield.md index e65b073a2..34db6c6be 100644 --- a/docs/de/docs/tutorial/dependencies/dependencies-with-yield.md +++ b/docs/de/docs/tutorial/dependencies/dependencies-with-yield.md @@ -184,6 +184,51 @@ Wenn Sie in dem Code der *Pfadoperation-Funktion* irgendeine Exception auslösen /// +## Frühes Beenden und `scope` { #early-exit-and-scope } + +Normalerweise wird der Exit-Code von Abhängigkeiten mit `yield` ausgeführt **nachdem die Response** an den Client gesendet wurde. + +Wenn Sie aber wissen, dass Sie die Abhängigkeit nach der Rückkehr aus der *Pfadoperation-Funktion* nicht mehr benötigen, können Sie `Depends(scope="function")` verwenden, um FastAPI mitzuteilen, dass es die Abhängigkeit nach der Rückkehr aus der *Pfadoperation-Funktion* schließen soll, jedoch **bevor** die **Response gesendet wird**. + +{* ../../docs_src/dependencies/tutorial008e_an_py39.py hl[12,16] *} + +`Depends()` erhält einen `scope`-Parameter, der sein kann: + +* `"function"`: startet die Abhängigkeit vor der *Pfadoperation-Funktion*, die den Request bearbeitet, beendet die Abhängigkeit nach dem Ende der *Pfadoperation-Funktion*, aber **bevor** die Response an den Client zurückgesendet wird. Die Abhängigkeitsfunktion wird also **um** die *Pfadoperation-**Funktion*** **herum** ausgeführt. +* `"request"`: startet die Abhängigkeit vor der *Pfadoperation-Funktion*, die den Request bearbeitet (ähnlich wie bei `"function"`), beendet sie jedoch **nachdem** die Response an den Client zurückgesendet wurde. Die Abhängigkeitsfunktion wird also **um** den **Request**- und Response-Zyklus **herum** ausgeführt. + +Wenn nicht angegeben und die Abhängigkeit `yield` hat, hat sie standardmäßig einen `scope` von `"request"`. + +### `scope` für Unterabhängigkeiten { #scope-for-sub-dependencies } + +Wenn Sie eine Abhängigkeit mit `scope="request"` (dem Default) deklarieren, muss jede Unterabhängigkeit ebenfalls einen `scope` von `"request"` haben. + +Eine Abhängigkeit mit `scope` von `"function"` kann jedoch Abhängigkeiten mit `scope` von `"function"` und `scope` von `"request"` haben. + +Das liegt daran, dass jede Abhängigkeit in der Lage sein muss, ihren Exit-Code vor den Unterabhängigkeiten auszuführen, da sie diese während ihres Exit-Codes möglicherweise noch verwenden muss. + +```mermaid +sequenceDiagram + +participant client as Client +participant dep_req as Abhängigkeit scope="request" +participant dep_func as Abhängigkeit scope="function" +participant operation as Pfadoperation + + client ->> dep_req: Startet den Request + Note over dep_req: Führt den Code bis zum yield aus + dep_req ->> dep_func: Reicht Abhängigkeit weiter + Note over dep_func: Führt den Code bis zum yield aus + dep_func ->> operation: Führt Pfadoperation mit Abhängigkeit aus + operation ->> dep_func: Kehrt aus Pfadoperation zurück + Note over dep_func: Führt Code nach yield aus + Note over dep_func: ✅ Abhängigkeit geschlossen + dep_func ->> client: Sendet Response an Client + Note over client: Response gesendet + Note over dep_req: Führt Code nach yield aus + Note over dep_req: ✅ Abhängigkeit geschlossen +``` + ## Abhängigkeiten mit `yield`, `HTTPException`, `except` und Hintergrundtasks { #dependencies-with-yield-httpexception-except-and-background-tasks } Abhängigkeiten mit `yield` haben sich im Laufe der Zeit weiterentwickelt, um verschiedene Anwendungsfälle abzudecken und einige Probleme zu beheben. diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 9380fb7d4..0d25ae643 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -7,6 +7,16 @@ hide: ## Latest Changes +### Translations + +* 🌐 Sync German docs. PR [#14317](https://github.com/fastapi/fastapi/pull/14317) by [@nilslindemann](https://github.com/nilslindemann). + +## 0.121.1 + +### Fixes + +* 🐛 Fix `Depends(func, scope='function')` for top level (parameterless) dependencies. PR [#14301](https://github.com/fastapi/fastapi/pull/14301) by [@luzzodev](https://github.com/luzzodev). + ### Docs * 📝 Upate docs for advanced dependencies with `yield`, noting the changes in 0.121.0, adding `scope`. PR [#14287](https://github.com/fastapi/fastapi/pull/14287) by [@tiangolo](https://github.com/tiangolo). diff --git a/fastapi/__init__.py b/fastapi/__init__.py index f4a952bf5..5c4804e19 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.121.0" +__version__ = "0.121.1" from starlette import status as status diff --git a/fastapi/dependencies/utils.py b/fastapi/dependencies/utils.py index 062719da9..163f9e794 100644 --- a/fastapi/dependencies/utils.py +++ b/fastapi/dependencies/utils.py @@ -136,7 +136,10 @@ def get_parameterless_sub_dependant(*, depends: params.Depends, path: str) -> De if isinstance(depends, params.Security) and depends.scopes: use_security_scopes.extend(depends.scopes) return get_dependant( - path=path, call=depends.dependency, security_scopes=use_security_scopes + path=path, + call=depends.dependency, + scope=depends.scope, + security_scopes=use_security_scopes, ) diff --git a/tests/test_dependency_yield_scope.py b/tests/test_dependency_yield_scope.py index a5227dd7a..d87164fe8 100644 --- a/tests/test_dependency_yield_scope.py +++ b/tests/test_dependency_yield_scope.py @@ -2,7 +2,7 @@ import json from typing import Any, Tuple import pytest -from fastapi import Depends, FastAPI +from fastapi import APIRouter, Depends, FastAPI, HTTPException from fastapi.exceptions import FastAPIError from fastapi.responses import StreamingResponse from fastapi.testclient import TestClient @@ -20,6 +20,11 @@ def dep_session() -> Any: s.open = False +def raise_after_yield() -> Any: + yield + raise HTTPException(status_code=503, detail="Exception after yield") + + SessionFuncDep = Annotated[Session, Depends(dep_session, scope="function")] SessionRequestDep = Annotated[Session, Depends(dep_session, scope="request")] SessionDefaultDep = Annotated[Session, Depends(dep_session)] @@ -64,6 +69,12 @@ RegularSessionsDep = Annotated[ ] app = FastAPI() +router = APIRouter() + + +@router.get("/") +def get_index(): + return {"status": "ok"} @app.get("/function-scope") @@ -124,6 +135,18 @@ def get_regular_function_scope(sessions: RegularSessionsDep) -> Any: return StreamingResponse(iter_data()) +app.include_router( + prefix="/router-scope-function", + router=router, + dependencies=[Depends(raise_after_yield, scope="function")], +) + +app.include_router( + prefix="/router-scope-request", + router=router, + dependencies=[Depends(raise_after_yield, scope="request")], +) + client = TestClient(app) @@ -182,3 +205,42 @@ def test_regular_function_scope() -> None: data = response.json() assert data["named_session_open"] is True assert data["session_open"] is False + + +def test_router_level_dep_scope_function() -> None: + response = client.get("/router-scope-function/") + assert response.status_code == 503 + assert response.json() == {"detail": "Exception after yield"} + + +def test_router_level_dep_scope_request() -> None: + with TestClient(app, raise_server_exceptions=False) as client: + response = client.get("/router-scope-request/") + assert response.status_code == 200 + assert response.json() == {"status": "ok"} + + +def test_app_level_dep_scope_function() -> None: + app = FastAPI(dependencies=[Depends(raise_after_yield, scope="function")]) + + @app.get("/app-scope-function") + def get_app_scope_function(): + return {"status": "ok"} + + with TestClient(app) as client: + response = client.get("/app-scope-function") + assert response.status_code == 503 + assert response.json() == {"detail": "Exception after yield"} + + +def test_app_level_dep_scope_request() -> None: + app = FastAPI(dependencies=[Depends(raise_after_yield, scope="request")]) + + @app.get("/app-scope-request") + def get_app_scope_request(): + return {"status": "ok"} + + with TestClient(app, raise_server_exceptions=False) as client: + response = client.get("/app-scope-request") + assert response.status_code == 200 + assert response.json() == {"status": "ok"}