mirror of https://github.com/tiangolo/fastapi.git
Add `default_dependency_scope` parameter to `FastAPI`
Add default_dependency_scope to allow the user to specify a default for dependencies declared without a scope.
This commit is contained in:
parent
95bceaa2fb
commit
e8381e94fb
|
|
@ -27,7 +27,7 @@ from fastapi.openapi.docs import (
|
|||
)
|
||||
from fastapi.openapi.utils import get_openapi
|
||||
from fastapi.params import Depends
|
||||
from fastapi.types import DecoratedCallable, IncEx
|
||||
from fastapi.types import DecoratedCallable, DependencyScope, IncEx
|
||||
from fastapi.utils import generate_unique_id
|
||||
from starlette.applications import Starlette
|
||||
from starlette.datastructures import State
|
||||
|
|
@ -844,6 +844,12 @@ class FastAPI(Starlette):
|
|||
"""
|
||||
),
|
||||
] = None,
|
||||
default_dependency_scope: Annotated[
|
||||
DependencyScope,
|
||||
Doc("""
|
||||
Default scope for dependencies that don't specify a scope.
|
||||
"""),
|
||||
] = None,
|
||||
**extra: Annotated[
|
||||
Any,
|
||||
Doc(
|
||||
|
|
@ -873,6 +879,7 @@ class FastAPI(Starlette):
|
|||
self.servers = servers or []
|
||||
self.separate_input_output_schemas = separate_input_output_schemas
|
||||
self.openapi_external_docs = openapi_external_docs
|
||||
self.default_dependency_scope = default_dependency_scope
|
||||
self.extra = extra
|
||||
self.openapi_version: Annotated[
|
||||
str,
|
||||
|
|
@ -1135,6 +1142,8 @@ class FastAPI(Starlette):
|
|||
async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None:
|
||||
if self.root_path:
|
||||
scope["root_path"] = self.root_path
|
||||
if self.default_dependency_scope:
|
||||
scope["fastapi_default_dependency_scope"] = self.default_dependency_scope
|
||||
await super().__call__(scope, receive, send)
|
||||
|
||||
def add_api_route(
|
||||
|
|
|
|||
|
|
@ -558,6 +558,7 @@ async def solve_dependencies(
|
|||
assert isinstance(request_astack, AsyncExitStack), "fastapi_inner_astack not found in request scope"
|
||||
function_astack = request.scope.get("fastapi_function_astack")
|
||||
assert isinstance(function_astack, AsyncExitStack), "fastapi_function_astack not found in request scope"
|
||||
default_dependency_scope = request.scope.get("fastapi_default_dependency_scope")
|
||||
values: dict[str, Any] = {}
|
||||
errors: list[Any] = []
|
||||
if response is None:
|
||||
|
|
@ -601,7 +602,8 @@ async def solve_dependencies(
|
|||
solved = dependency_cache[sub_dependant.cache_key]
|
||||
elif use_sub_dependant.is_gen_callable or use_sub_dependant.is_async_gen_callable:
|
||||
use_astack = request_astack
|
||||
if sub_dependant.scope == "function":
|
||||
sub_dependant_scope = sub_dependant.scope or default_dependency_scope
|
||||
if sub_dependant_scope == "function":
|
||||
use_astack = function_astack
|
||||
solved = await _solve_generator(
|
||||
dependant=use_sub_dependant,
|
||||
|
|
|
|||
|
|
@ -243,3 +243,51 @@ def test_app_level_dep_scope_request() -> None:
|
|||
response = client.get("/app-scope-request")
|
||||
assert response.status_code == 200
|
||||
assert response.json() == {"status": "ok"}
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"default_scope,expected_is_open",
|
||||
(
|
||||
(
|
||||
None,
|
||||
True,
|
||||
), # When default_dependency_scope is unset, scope defaults to "request"
|
||||
("function", False),
|
||||
("request", True),
|
||||
),
|
||||
)
|
||||
def test_default_dependency_scope(default_scope, expected_is_open) -> None:
|
||||
app = FastAPI(default_dependency_scope=default_scope)
|
||||
|
||||
endpoint = "/default-scope"
|
||||
|
||||
@app.get(endpoint)
|
||||
def _endpoint(session: SessionDefaultDep) -> Any:
|
||||
def iter_data():
|
||||
yield json.dumps({"is_open": session.open})
|
||||
|
||||
return StreamingResponse(iter_data())
|
||||
|
||||
with TestClient(app, raise_server_exceptions=False) as client:
|
||||
response = client.get(endpoint)
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
assert data["is_open"] is expected_is_open
|
||||
|
||||
def test_override_default_dependency_scope() -> None:
|
||||
app = FastAPI(default_dependency_scope="function")
|
||||
|
||||
endpoint = "/request-scope"
|
||||
|
||||
@app.get(endpoint)
|
||||
def _endpoint(session: SessionRequestDep) -> Any:
|
||||
def iter_data():
|
||||
yield json.dumps({"is_open": session.open})
|
||||
|
||||
return StreamingResponse(iter_data())
|
||||
|
||||
with TestClient(app, raise_server_exceptions=False) as client:
|
||||
response = client.get(endpoint)
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
assert data["is_open"] is True
|
||||
|
|
|
|||
Loading…
Reference in New Issue