mirror of https://github.com/tiangolo/fastapi.git
✨ Support Annotated dependencies in APIRoute
This commit is contained in:
parent
c9b8f6ff2d
commit
0253ac7273
|
|
@ -333,7 +333,7 @@ class FastAPI(Starlette):
|
|||
),
|
||||
] = None,
|
||||
dependencies: Annotated[
|
||||
Optional[Sequence[Depends | Any]],
|
||||
Optional[Sequence[Depends | routing.AnnotatedType]],
|
||||
Doc(
|
||||
"""
|
||||
A list of global dependencies, they will be applied to each
|
||||
|
|
@ -1141,7 +1141,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[Depends | routing.AnnotatedType]] = None,
|
||||
summary: Optional[str] = None,
|
||||
description: Optional[str] = None,
|
||||
response_description: str = "Successful Response",
|
||||
|
|
@ -1199,7 +1199,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[Depends | routing.AnnotatedType]] = None,
|
||||
summary: Optional[str] = None,
|
||||
description: Optional[str] = None,
|
||||
response_description: str = "Successful Response",
|
||||
|
|
@ -1258,7 +1258,7 @@ class FastAPI(Starlette):
|
|||
endpoint: Callable[..., Any],
|
||||
name: Optional[str] = None,
|
||||
*,
|
||||
dependencies: Optional[Sequence[Depends]] = None,
|
||||
dependencies: Optional[Sequence[Depends | routing.AnnotatedType]] = None,
|
||||
) -> None:
|
||||
self.router.add_api_websocket_route(
|
||||
path,
|
||||
|
|
@ -1287,7 +1287,7 @@ class FastAPI(Starlette):
|
|||
] = None,
|
||||
*,
|
||||
dependencies: Annotated[
|
||||
Optional[Sequence[Depends]],
|
||||
Optional[Sequence[Depends | routing.AnnotatedType]],
|
||||
Doc(
|
||||
"""
|
||||
A list of dependencies (using `Depends()`) to be used for this
|
||||
|
|
@ -1352,7 +1352,7 @@ class FastAPI(Starlette):
|
|||
),
|
||||
] = None,
|
||||
dependencies: Annotated[
|
||||
Optional[Sequence[Depends]],
|
||||
Optional[Sequence[Depends | routing.AnnotatedType]],
|
||||
Doc(
|
||||
"""
|
||||
A list of dependencies (using `Depends()`) to be applied to all the
|
||||
|
|
@ -1611,7 +1611,7 @@ class FastAPI(Starlette):
|
|||
),
|
||||
] = None,
|
||||
dependencies: Annotated[
|
||||
Optional[Sequence[Depends]],
|
||||
Optional[Sequence[Depends | routing.AnnotatedType]],
|
||||
Doc(
|
||||
"""
|
||||
A list of dependencies (using `Depends()`) to be applied to the
|
||||
|
|
@ -1984,7 +1984,7 @@ class FastAPI(Starlette):
|
|||
),
|
||||
] = None,
|
||||
dependencies: Annotated[
|
||||
Optional[Sequence[Depends]],
|
||||
Optional[Sequence[Depends | routing.AnnotatedType]],
|
||||
Doc(
|
||||
"""
|
||||
A list of dependencies (using `Depends()`) to be applied to the
|
||||
|
|
@ -2362,7 +2362,7 @@ class FastAPI(Starlette):
|
|||
),
|
||||
] = None,
|
||||
dependencies: Annotated[
|
||||
Optional[Sequence[Depends]],
|
||||
Optional[Sequence[Depends | routing.AnnotatedType]],
|
||||
Doc(
|
||||
"""
|
||||
A list of dependencies (using `Depends()`) to be applied to the
|
||||
|
|
@ -2740,7 +2740,7 @@ class FastAPI(Starlette):
|
|||
),
|
||||
] = None,
|
||||
dependencies: Annotated[
|
||||
Optional[Sequence[Depends]],
|
||||
Optional[Sequence[Depends | routing.AnnotatedType]],
|
||||
Doc(
|
||||
"""
|
||||
A list of dependencies (using `Depends()`) to be applied to the
|
||||
|
|
@ -3113,7 +3113,7 @@ class FastAPI(Starlette):
|
|||
),
|
||||
] = None,
|
||||
dependencies: Annotated[
|
||||
Optional[Sequence[Depends]],
|
||||
Optional[Sequence[Depends | routing.AnnotatedType]],
|
||||
Doc(
|
||||
"""
|
||||
A list of dependencies (using `Depends()`) to be applied to the
|
||||
|
|
@ -3486,7 +3486,7 @@ class FastAPI(Starlette):
|
|||
),
|
||||
] = None,
|
||||
dependencies: Annotated[
|
||||
Optional[Sequence[Depends]],
|
||||
Optional[Sequence[Depends | routing.AnnotatedType]],
|
||||
Doc(
|
||||
"""
|
||||
A list of dependencies (using `Depends()`) to be applied to the
|
||||
|
|
@ -3859,7 +3859,7 @@ class FastAPI(Starlette):
|
|||
),
|
||||
] = None,
|
||||
dependencies: Annotated[
|
||||
Optional[Sequence[Depends]],
|
||||
Optional[Sequence[Depends | routing.AnnotatedType]],
|
||||
Doc(
|
||||
"""
|
||||
A list of dependencies (using `Depends()`) to be applied to the
|
||||
|
|
@ -4237,7 +4237,7 @@ class FastAPI(Starlette):
|
|||
),
|
||||
] = None,
|
||||
dependencies: Annotated[
|
||||
Optional[Sequence[Depends]],
|
||||
Optional[Sequence[Depends | routing.AnnotatedType]],
|
||||
Doc(
|
||||
"""
|
||||
A list of dependencies (using `Depends()`) to be applied to the
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ from typing import (
|
|||
List,
|
||||
Mapping,
|
||||
Optional,
|
||||
Protocol,
|
||||
Sequence,
|
||||
Set,
|
||||
Tuple,
|
||||
|
|
@ -464,6 +465,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,
|
||||
|
|
@ -471,13 +476,15 @@ class APIWebSocketRoute(routing.WebSocketRoute):
|
|||
endpoint: Callable[..., Any],
|
||||
*,
|
||||
name: Optional[str] = None,
|
||||
dependencies: Optional[Sequence[params.Depends]] = None,
|
||||
dependencies: Optional[Sequence[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)
|
||||
for depends in self.dependencies[::-1]:
|
||||
|
|
@ -513,7 +520,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[params.Depends | AnnotatedType]] = None,
|
||||
summary: Optional[str] = None,
|
||||
description: Optional[str] = None,
|
||||
response_description: str = "Successful Response",
|
||||
|
|
@ -606,7 +613,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"
|
||||
|
|
@ -671,7 +680,7 @@ class APIRoute(routing.Route):
|
|||
return match, child_scope
|
||||
|
||||
|
||||
def get_depends_from_annotated(dep: params.Depends | Any) -> params.Depends:
|
||||
def get_depends_from_annotated(dep: params.Depends | AnnotatedType) -> params.Depends:
|
||||
if isinstance(dep, params.Depends):
|
||||
return dep
|
||||
d = analyze_param(
|
||||
|
|
@ -733,7 +742,7 @@ class APIRouter(routing.Router):
|
|||
),
|
||||
] = None,
|
||||
dependencies: Annotated[
|
||||
Optional[Sequence[params.Depends | Any]],
|
||||
Optional[Sequence[params.Depends | AnnotatedType]],
|
||||
Doc(
|
||||
"""
|
||||
A list of dependencies to be applied to all the *path operations* in
|
||||
|
|
@ -987,7 +996,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[params.Depends | AnnotatedType]] = None,
|
||||
summary: Optional[str] = None,
|
||||
description: Optional[str] = None,
|
||||
response_description: str = "Successful Response",
|
||||
|
|
@ -1024,7 +1033,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)
|
||||
|
|
@ -1068,7 +1079,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[params.Depends | AnnotatedType]] = None,
|
||||
summary: Optional[str] = None,
|
||||
description: Optional[str] = None,
|
||||
response_description: str = "Successful Response",
|
||||
|
|
@ -1129,11 +1140,13 @@ class APIRouter(routing.Router):
|
|||
endpoint: Callable[..., Any],
|
||||
name: Optional[str] = None,
|
||||
*,
|
||||
dependencies: Optional[Sequence[params.Depends]] = None,
|
||||
dependencies: Optional[Sequence[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,
|
||||
|
|
@ -1164,7 +1177,7 @@ class APIRouter(routing.Router):
|
|||
] = None,
|
||||
*,
|
||||
dependencies: Annotated[
|
||||
Optional[Sequence[params.Depends]],
|
||||
Optional[Sequence[params.Depends | AnnotatedType]],
|
||||
Doc(
|
||||
"""
|
||||
A list of dependencies (using `Depends()`) to be used for this
|
||||
|
|
@ -1240,7 +1253,7 @@ class APIRouter(routing.Router):
|
|||
),
|
||||
] = None,
|
||||
dependencies: Annotated[
|
||||
Optional[Sequence[params.Depends]],
|
||||
Optional[Sequence[params.Depends | AnnotatedType]],
|
||||
Doc(
|
||||
"""
|
||||
A list of dependencies (using `Depends()`) to be applied to all the
|
||||
|
|
@ -1386,7 +1399,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 = []
|
||||
|
|
@ -1442,7 +1457,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(
|
||||
|
|
@ -1538,7 +1555,7 @@ class APIRouter(routing.Router):
|
|||
),
|
||||
] = None,
|
||||
dependencies: Annotated[
|
||||
Optional[Sequence[params.Depends]],
|
||||
Optional[Sequence[params.Depends | AnnotatedType]],
|
||||
Doc(
|
||||
"""
|
||||
A list of dependencies (using `Depends()`) to be applied to the
|
||||
|
|
@ -1915,7 +1932,7 @@ class APIRouter(routing.Router):
|
|||
),
|
||||
] = None,
|
||||
dependencies: Annotated[
|
||||
Optional[Sequence[params.Depends]],
|
||||
Optional[Sequence[params.Depends | AnnotatedType]],
|
||||
Doc(
|
||||
"""
|
||||
A list of dependencies (using `Depends()`) to be applied to the
|
||||
|
|
@ -2297,7 +2314,7 @@ class APIRouter(routing.Router):
|
|||
),
|
||||
] = None,
|
||||
dependencies: Annotated[
|
||||
Optional[Sequence[params.Depends]],
|
||||
Optional[Sequence[params.Depends | AnnotatedType]],
|
||||
Doc(
|
||||
"""
|
||||
A list of dependencies (using `Depends()`) to be applied to the
|
||||
|
|
@ -2679,7 +2696,7 @@ class APIRouter(routing.Router):
|
|||
),
|
||||
] = None,
|
||||
dependencies: Annotated[
|
||||
Optional[Sequence[params.Depends]],
|
||||
Optional[Sequence[params.Depends | AnnotatedType]],
|
||||
Doc(
|
||||
"""
|
||||
A list of dependencies (using `Depends()`) to be applied to the
|
||||
|
|
@ -3056,7 +3073,7 @@ class APIRouter(routing.Router):
|
|||
),
|
||||
] = None,
|
||||
dependencies: Annotated[
|
||||
Optional[Sequence[params.Depends]],
|
||||
Optional[Sequence[params.Depends | AnnotatedType]],
|
||||
Doc(
|
||||
"""
|
||||
A list of dependencies (using `Depends()`) to be applied to the
|
||||
|
|
@ -3433,7 +3450,7 @@ class APIRouter(routing.Router):
|
|||
),
|
||||
] = None,
|
||||
dependencies: Annotated[
|
||||
Optional[Sequence[params.Depends]],
|
||||
Optional[Sequence[params.Depends | AnnotatedType]],
|
||||
Doc(
|
||||
"""
|
||||
A list of dependencies (using `Depends()`) to be applied to the
|
||||
|
|
@ -3815,7 +3832,7 @@ class APIRouter(routing.Router):
|
|||
),
|
||||
] = None,
|
||||
dependencies: Annotated[
|
||||
Optional[Sequence[params.Depends]],
|
||||
Optional[Sequence[params.Depends | AnnotatedType]],
|
||||
Doc(
|
||||
"""
|
||||
A list of dependencies (using `Depends()`) to be applied to the
|
||||
|
|
@ -4197,7 +4214,7 @@ class APIRouter(routing.Router):
|
|||
),
|
||||
] = None,
|
||||
dependencies: Annotated[
|
||||
Optional[Sequence[params.Depends]],
|
||||
Optional[Sequence[params.Depends | AnnotatedType]],
|
||||
Doc(
|
||||
"""
|
||||
A list of dependencies (using `Depends()`) to be applied to the
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ def get_value() -> int:
|
|||
ValueDep = Annotated[int, Depends(get_value)]
|
||||
|
||||
|
||||
router = APIRouter(dependencies=[ValueDep, Depends(lambda: "sdfgh")])
|
||||
router = APIRouter(dependencies=[Depends(lambda: "sdfgh"), ValueDep])
|
||||
|
||||
|
||||
@router.get("/")
|
||||
|
|
@ -26,6 +26,8 @@ def no_dep():
|
|||
app = FastAPI()
|
||||
app.include_router(router)
|
||||
|
||||
router.post("/", dependencies=[Depends(lambda: None)])
|
||||
|
||||
|
||||
def test_apirouter_annotated_dependencies():
|
||||
client = TestClient(app)
|
||||
|
|
|
|||
Loading…
Reference in New Issue