This commit is contained in:
Profianton 2025-12-16 21:09:32 +00:00 committed by GitHub
commit 498e8d82b1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 124 additions and 41 deletions

View File

@ -339,7 +339,7 @@ class FastAPI(Starlette):
),
] = None,
dependencies: Annotated[
Optional[Sequence[Depends]],
Optional[Sequence[Union[Depends, routing.AnnotatedType]]],
Doc(
"""
A list of global dependencies, they will be applied to each
@ -351,11 +351,12 @@ class FastAPI(Starlette):
**Example**
```python
from typing import Annotated
from fastapi import Depends, FastAPI
from .dependencies import func_dep_1, func_dep_2
app = FastAPI(dependencies=[Depends(func_dep_1), Depends(func_dep_2)])
annotated_dep=Annotated[str,Depends(lambda:"annotated")]
app = FastAPI(dependencies=[Depends(func_dep_1), Depends(func_dep_2),annotated_dep])
```
"""
),
@ -1146,7 +1147,7 @@ class FastAPI(Starlette):
response_model: Any = Default(None),
status_code: Optional[int] = None,
tags: Optional[List[Union[str, Enum]]] = None,
dependencies: Optional[Sequence[Depends]] = None,
dependencies: Optional[Sequence[Union[Depends, routing.AnnotatedType]]] = None,
summary: Optional[str] = None,
description: Optional[str] = None,
response_description: str = "Successful Response",
@ -1204,7 +1205,7 @@ class FastAPI(Starlette):
response_model: Any = Default(None),
status_code: Optional[int] = None,
tags: Optional[List[Union[str, Enum]]] = None,
dependencies: Optional[Sequence[Depends]] = None,
dependencies: Optional[Sequence[Union[Depends, routing.AnnotatedType]]] = None,
summary: Optional[str] = None,
description: Optional[str] = None,
response_description: str = "Successful Response",
@ -1263,7 +1264,7 @@ class FastAPI(Starlette):
endpoint: Callable[..., Any],
name: Optional[str] = None,
*,
dependencies: Optional[Sequence[Depends]] = None,
dependencies: Optional[Sequence[Union[Depends, routing.AnnotatedType]]] = None,
) -> None:
self.router.add_api_websocket_route(
path,
@ -1292,7 +1293,7 @@ class FastAPI(Starlette):
] = None,
*,
dependencies: Annotated[
Optional[Sequence[Depends]],
Optional[Sequence[Union[Depends, routing.AnnotatedType]]],
Doc(
"""
A list of dependencies (using `Depends()`) to be used for this
@ -1357,7 +1358,7 @@ class FastAPI(Starlette):
),
] = None,
dependencies: Annotated[
Optional[Sequence[Depends]],
Optional[Sequence[Union[Depends, routing.AnnotatedType]]],
Doc(
"""
A list of dependencies (using `Depends()`) to be applied to all the
@ -1616,7 +1617,7 @@ class FastAPI(Starlette):
),
] = None,
dependencies: Annotated[
Optional[Sequence[Depends]],
Optional[Sequence[Union[Depends, routing.AnnotatedType]]],
Doc(
"""
A list of dependencies (using `Depends()`) to be applied to the
@ -1989,7 +1990,7 @@ class FastAPI(Starlette):
),
] = None,
dependencies: Annotated[
Optional[Sequence[Depends]],
Optional[Sequence[Union[Depends, routing.AnnotatedType]]],
Doc(
"""
A list of dependencies (using `Depends()`) to be applied to the
@ -2367,7 +2368,7 @@ class FastAPI(Starlette):
),
] = None,
dependencies: Annotated[
Optional[Sequence[Depends]],
Optional[Sequence[Union[Depends, routing.AnnotatedType]]],
Doc(
"""
A list of dependencies (using `Depends()`) to be applied to the
@ -2745,7 +2746,7 @@ class FastAPI(Starlette):
),
] = None,
dependencies: Annotated[
Optional[Sequence[Depends]],
Optional[Sequence[Union[Depends, routing.AnnotatedType]]],
Doc(
"""
A list of dependencies (using `Depends()`) to be applied to the
@ -3118,7 +3119,7 @@ class FastAPI(Starlette):
),
] = None,
dependencies: Annotated[
Optional[Sequence[Depends]],
Optional[Sequence[Union[Depends, routing.AnnotatedType]]],
Doc(
"""
A list of dependencies (using `Depends()`) to be applied to the
@ -3491,7 +3492,7 @@ class FastAPI(Starlette):
),
] = None,
dependencies: Annotated[
Optional[Sequence[Depends]],
Optional[Sequence[Union[Depends, routing.AnnotatedType]]],
Doc(
"""
A list of dependencies (using `Depends()`) to be applied to the
@ -3864,7 +3865,7 @@ class FastAPI(Starlette):
),
] = None,
dependencies: Annotated[
Optional[Sequence[Depends]],
Optional[Sequence[Union[Depends, routing.AnnotatedType]]],
Doc(
"""
A list of dependencies (using `Depends()`) to be applied to the
@ -4242,7 +4243,7 @@ class FastAPI(Starlette):
),
] = None,
dependencies: Annotated[
Optional[Sequence[Depends]],
Optional[Sequence[Union[Depends, routing.AnnotatedType]]],
Doc(
"""
A list of dependencies (using `Depends()`) to be applied to the

View File

@ -16,6 +16,7 @@ from typing import (
List,
Mapping,
Optional,
Protocol,
Sequence,
Set,
Tuple,
@ -37,6 +38,7 @@ from fastapi.datastructures import Default, DefaultPlaceholder
from fastapi.dependencies.models import Dependant
from fastapi.dependencies.utils import (
_should_embed_body_fields,
analyze_param,
get_body_field,
get_dependant,
get_flat_dependant,
@ -515,6 +517,10 @@ def get_websocket_app(
return app
class AnnotatedType(Protocol):
"""this forces mypy to check if Any is handled correctly"""
class APIWebSocketRoute(routing.WebSocketRoute):
def __init__(
self,
@ -522,13 +528,15 @@ class APIWebSocketRoute(routing.WebSocketRoute):
endpoint: Callable[..., Any],
*,
name: Optional[str] = None,
dependencies: Optional[Sequence[params.Depends]] = None,
dependencies: Optional[Sequence[Union[params.Depends, AnnotatedType]]] = None,
dependency_overrides_provider: Optional[Any] = None,
) -> None:
self.path = path
self.endpoint = endpoint
self.name = get_name(endpoint) if name is None else name
self.dependencies = list(dependencies or [])
self.dependencies = [
get_depends_from_annotated(dep) for dep in dependencies or []
]
self.path_regex, self.path_format, self.param_convertors = compile_path(path)
self.dependant = get_dependant(
path=self.path_format, call=self.endpoint, scope="function"
@ -566,7 +574,7 @@ class APIRoute(routing.Route):
response_model: Any = Default(None),
status_code: Optional[int] = None,
tags: Optional[List[Union[str, Enum]]] = None,
dependencies: Optional[Sequence[params.Depends]] = None,
dependencies: Optional[Sequence[Union[params.Depends, AnnotatedType]]] = None,
summary: Optional[str] = None,
description: Optional[str] = None,
response_description: str = "Successful Response",
@ -659,7 +667,9 @@ class APIRoute(routing.Route):
else:
self.response_field = None # type: ignore
self.secure_cloned_response_field = None
self.dependencies = list(dependencies or [])
self.dependencies = [
get_depends_from_annotated(dep) for dep in dependencies or []
]
self.description = description or inspect.cleandoc(self.endpoint.__doc__ or "")
# if a "form feed" character (page break) is found in the description text,
# truncate description text to the content preceding the first "form feed"
@ -726,6 +736,24 @@ class APIRoute(routing.Route):
return match, child_scope
def get_depends_from_annotated(
dep: Union[params.Depends, AnnotatedType],
) -> params.Depends:
if isinstance(dep, params.Depends):
return dep
d = analyze_param(
param_name="APIRouter Dependency",
annotation=dep,
value=inspect.Signature.empty,
is_path_param=False,
).depends
assert d is not None, (
"APIRouter dependency must be a Depends or be Annotated with Depends"
)
return d
class APIRouter(routing.Router):
"""
`APIRouter` class, used to group *path operations*, for example to structure
@ -772,11 +800,15 @@ class APIRouter(routing.Router):
),
] = None,
dependencies: Annotated[
Optional[Sequence[params.Depends]],
Optional[Sequence[Union[params.Depends, AnnotatedType]]],
Doc(
"""
A list of dependencies (using `Depends()`) to be applied to all the
*path operations* in this router.
A list of dependencies to be applied to all the *path operations* in
this router.
Dependencies can be provided as `Depends(...)` instances, or using
`Annotated[..., Depends(...)]`. FastAPI will analyze and convert
these automatically when the router is included.
Read more about it in the
[FastAPI docs for Bigger Applications - Multiple Files](https://fastapi.tiangolo.com/tutorial/bigger-applications/#include-an-apirouter-with-a-custom-prefix-tags-responses-and-dependencies).
@ -983,7 +1015,9 @@ class APIRouter(routing.Router):
)
self.prefix = prefix
self.tags: List[Union[str, Enum]] = tags or []
self.dependencies = list(dependencies or [])
self.dependencies = [
get_depends_from_annotated(dep) for dep in dependencies or []
]
self.deprecated = deprecated
self.include_in_schema = include_in_schema
self.responses = responses or {}
@ -1020,7 +1054,7 @@ class APIRouter(routing.Router):
response_model: Any = Default(None),
status_code: Optional[int] = None,
tags: Optional[List[Union[str, Enum]]] = None,
dependencies: Optional[Sequence[params.Depends]] = None,
dependencies: Optional[Sequence[Union[params.Depends, AnnotatedType]]] = None,
summary: Optional[str] = None,
description: Optional[str] = None,
response_description: str = "Successful Response",
@ -1057,7 +1091,9 @@ class APIRouter(routing.Router):
current_tags.extend(tags)
current_dependencies = self.dependencies.copy()
if dependencies:
current_dependencies.extend(dependencies)
current_dependencies.extend(
[get_depends_from_annotated(dep) for dep in dependencies]
)
current_callbacks = self.callbacks.copy()
if callbacks:
current_callbacks.extend(callbacks)
@ -1101,7 +1137,7 @@ class APIRouter(routing.Router):
response_model: Any = Default(None),
status_code: Optional[int] = None,
tags: Optional[List[Union[str, Enum]]] = None,
dependencies: Optional[Sequence[params.Depends]] = None,
dependencies: Optional[Sequence[Union[params.Depends, AnnotatedType]]] = None,
summary: Optional[str] = None,
description: Optional[str] = None,
response_description: str = "Successful Response",
@ -1162,11 +1198,13 @@ class APIRouter(routing.Router):
endpoint: Callable[..., Any],
name: Optional[str] = None,
*,
dependencies: Optional[Sequence[params.Depends]] = None,
dependencies: Optional[Sequence[Union[params.Depends, AnnotatedType]]] = None,
) -> None:
current_dependencies = self.dependencies.copy()
if dependencies:
current_dependencies.extend(dependencies)
current_dependencies.extend(
[get_depends_from_annotated(dep) for dep in dependencies]
)
route = APIWebSocketRoute(
self.prefix + path,
@ -1197,7 +1235,7 @@ class APIRouter(routing.Router):
] = None,
*,
dependencies: Annotated[
Optional[Sequence[params.Depends]],
Optional[Sequence[Union[params.Depends, AnnotatedType]]],
Doc(
"""
A list of dependencies (using `Depends()`) to be used for this
@ -1273,7 +1311,7 @@ class APIRouter(routing.Router):
),
] = None,
dependencies: Annotated[
Optional[Sequence[params.Depends]],
Optional[Sequence[Union[params.Depends, AnnotatedType]]],
Doc(
"""
A list of dependencies (using `Depends()`) to be applied to all the
@ -1419,7 +1457,9 @@ class APIRouter(routing.Router):
current_tags.extend(route.tags)
current_dependencies: List[params.Depends] = []
if dependencies:
current_dependencies.extend(dependencies)
current_dependencies.extend(
[get_depends_from_annotated(dep) for dep in dependencies]
)
if route.dependencies:
current_dependencies.extend(route.dependencies)
current_callbacks = []
@ -1475,7 +1515,9 @@ class APIRouter(routing.Router):
elif isinstance(route, APIWebSocketRoute):
current_dependencies = []
if dependencies:
current_dependencies.extend(dependencies)
current_dependencies.extend(
[get_depends_from_annotated(dep) for dep in dependencies]
)
if route.dependencies:
current_dependencies.extend(route.dependencies)
self.add_api_websocket_route(
@ -1571,7 +1613,7 @@ class APIRouter(routing.Router):
),
] = None,
dependencies: Annotated[
Optional[Sequence[params.Depends]],
Optional[Sequence[Union[params.Depends, AnnotatedType]]],
Doc(
"""
A list of dependencies (using `Depends()`) to be applied to the
@ -1948,7 +1990,7 @@ class APIRouter(routing.Router):
),
] = None,
dependencies: Annotated[
Optional[Sequence[params.Depends]],
Optional[Sequence[Union[params.Depends, AnnotatedType]]],
Doc(
"""
A list of dependencies (using `Depends()`) to be applied to the
@ -2330,7 +2372,7 @@ class APIRouter(routing.Router):
),
] = None,
dependencies: Annotated[
Optional[Sequence[params.Depends]],
Optional[Sequence[Union[params.Depends, AnnotatedType]]],
Doc(
"""
A list of dependencies (using `Depends()`) to be applied to the
@ -2712,7 +2754,7 @@ class APIRouter(routing.Router):
),
] = None,
dependencies: Annotated[
Optional[Sequence[params.Depends]],
Optional[Sequence[Union[params.Depends, AnnotatedType]]],
Doc(
"""
A list of dependencies (using `Depends()`) to be applied to the
@ -3089,7 +3131,7 @@ class APIRouter(routing.Router):
),
] = None,
dependencies: Annotated[
Optional[Sequence[params.Depends]],
Optional[Sequence[Union[params.Depends, AnnotatedType]]],
Doc(
"""
A list of dependencies (using `Depends()`) to be applied to the
@ -3466,7 +3508,7 @@ class APIRouter(routing.Router):
),
] = None,
dependencies: Annotated[
Optional[Sequence[params.Depends]],
Optional[Sequence[Union[params.Depends, AnnotatedType]]],
Doc(
"""
A list of dependencies (using `Depends()`) to be applied to the
@ -3848,7 +3890,7 @@ class APIRouter(routing.Router):
),
] = None,
dependencies: Annotated[
Optional[Sequence[params.Depends]],
Optional[Sequence[Union[params.Depends, AnnotatedType]]],
Doc(
"""
A list of dependencies (using `Depends()`) to be applied to the
@ -4230,7 +4272,7 @@ class APIRouter(routing.Router):
),
] = None,
dependencies: Annotated[
Optional[Sequence[params.Depends]],
Optional[Sequence[Union[params.Depends, AnnotatedType]]],
Doc(
"""
A list of dependencies (using `Depends()`) to be applied to the

View File

@ -0,0 +1,40 @@
from fastapi import APIRouter, Depends, FastAPI
from fastapi.testclient import TestClient
from typing_extensions import Annotated
def get_value() -> int:
return 1
ValueDep = Annotated[int, Depends(get_value)]
router = APIRouter(dependencies=[Depends(lambda: "sdfgh"), ValueDep])
@router.get("/")
def read_root(dep: ValueDep):
return {"dep": dep}
@router.get("/no_dep")
def no_dep():
return {"status": 200}
app = FastAPI()
app.include_router(router)
router.post("/", dependencies=[Depends(lambda: None)])
def test_apirouter_annotated_dependencies():
client = TestClient(app)
response = client.get("/")
assert response.status_code == 200
assert response.json() == {"dep": 1}
response = client.get("/no_dep")
assert response.status_code == 200
assert response.json() == {"status": 200}