You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

920 lines
28 KiB

import warnings
from contextlib import asynccontextmanager
from time import sleep
from typing import Any, AsyncGenerator, Dict, List, Tuple
import pytest
from fastapi import (
APIRouter,
BackgroundTasks,
Body,
Cookie,
Depends,
FastAPI,
File,
Form,
Header,
Path,
Query,
Request,
WebSocket,
)
from fastapi.dependencies.utils import get_endpoint_dependant
from fastapi.exceptions import (
DependencyScopeConflict,
InvalidDependencyScope,
UninitializedLifespanDependency,
)
from fastapi.params import Security
from fastapi.security import SecurityScopes
from fastapi.testclient import TestClient
from typing_extensions import Annotated, Literal
from tests.test_lifespan_scoped_dependencies.testing_utilities import (
DependencyFactory,
DependencyStyle,
IntentionallyBadDependency,
create_endpoint_0_annotations,
create_endpoint_1_annotation,
create_endpoint_2_annotations,
create_endpoint_3_annotations,
use_endpoint,
use_websocket,
)
def expect_correct_amount_of_dependency_activations(
*,
app: FastAPI,
dependency_factory: DependencyFactory,
urls_and_responses: List[Tuple[str, Any]],
expected_activation_times: int,
is_websocket: bool,
) -> None:
assert dependency_factory.activation_times == 0
assert dependency_factory.deactivation_times == 0
with TestClient(app) as client:
assert dependency_factory.activation_times == expected_activation_times
assert dependency_factory.deactivation_times == 0
for url, expected_response in urls_and_responses:
if is_websocket:
assert use_websocket(client, url) == expected_response
else:
assert use_endpoint(client, url) == expected_response
assert dependency_factory.activation_times == expected_activation_times
assert dependency_factory.deactivation_times == 0
assert dependency_factory.activation_times == expected_activation_times
if dependency_factory.dependency_style not in (
DependencyStyle.SYNC_FUNCTION,
DependencyStyle.ASYNC_FUNCTION,
):
assert dependency_factory.deactivation_times == expected_activation_times
@pytest.mark.parametrize("is_websocket", [True, False], ids=["Websocket", "Endpoint"])
@pytest.mark.parametrize(
"use_cache", [True, False], ids=["With Cache", "Without Cache"]
)
@pytest.mark.parametrize("dependency_style", list(DependencyStyle))
@pytest.mark.parametrize("routing_style", ["app_endpoint", "router_endpoint"])
def test_endpoint_dependencies(
dependency_style: DependencyStyle,
routing_style,
use_cache,
is_websocket: bool,
):
dependency_factory = DependencyFactory(dependency_style)
app = FastAPI()
if routing_style == "app_endpoint":
router = app
else:
router = APIRouter()
create_endpoint_1_annotation(
router=router,
path="/test",
is_websocket=is_websocket,
annotation=Annotated[
None,
Depends(
dependency_factory.get_dependency(),
dependency_scope="lifespan",
use_cache=use_cache,
),
],
expected_value=1,
)
if routing_style == "router_endpoint":
app.include_router(router)
expect_correct_amount_of_dependency_activations(
app=app,
dependency_factory=dependency_factory,
urls_and_responses=[("/test", 1)] * 2,
expected_activation_times=1,
is_websocket=is_websocket,
)
@pytest.mark.parametrize("is_websocket", [True, False], ids=["Websocket", "Endpoint"])
@pytest.mark.parametrize("dependency_duplication", [1, 2])
@pytest.mark.parametrize("use_cache", [True, False])
@pytest.mark.parametrize("dependency_style", list(DependencyStyle))
@pytest.mark.parametrize("routing_style", ["app", "router"])
def test_router_dependencies(
dependency_style: DependencyStyle,
routing_style,
use_cache,
dependency_duplication,
is_websocket: bool,
):
dependency_factory = DependencyFactory(dependency_style)
depends = Depends(
dependency_factory.get_dependency(),
dependency_scope="lifespan",
use_cache=use_cache,
)
if routing_style == "app":
app = FastAPI(dependencies=[depends] * dependency_duplication)
create_endpoint_0_annotations(
router=app, path="/test", is_websocket=is_websocket
)
else:
app = FastAPI()
router = APIRouter(dependencies=[depends] * dependency_duplication)
create_endpoint_0_annotations(
router=router, path="/test", is_websocket=is_websocket
)
app.include_router(router)
expect_correct_amount_of_dependency_activations(
app=app,
dependency_factory=dependency_factory,
urls_and_responses=[("/test", None)] * 2,
expected_activation_times=1 if use_cache else dependency_duplication,
is_websocket=is_websocket,
)
@pytest.mark.parametrize("is_websocket", [True, False], ids=["Websocket", "Endpoint"])
@pytest.mark.parametrize("use_cache", [True, False])
@pytest.mark.parametrize("dependency_style", list(DependencyStyle))
@pytest.mark.parametrize("routing_style", ["app", "router"])
@pytest.mark.parametrize("main_dependency_scope", ["endpoint", "lifespan"])
def test_dependency_cache_in_same_dependency(
dependency_style: DependencyStyle,
routing_style,
use_cache,
main_dependency_scope: Literal["endpoint", "lifespan"],
is_websocket: bool,
):
dependency_factory = DependencyFactory(dependency_style)
depends = Depends(
dependency_factory.get_dependency(),
dependency_scope="lifespan",
use_cache=use_cache,
)
app = FastAPI()
if routing_style == "app":
router = app
else:
router = APIRouter()
async def dependency(
sub_dependency1: Annotated[int, depends],
sub_dependency2: Annotated[int, depends],
) -> List[int]:
return [sub_dependency1, sub_dependency2]
create_endpoint_1_annotation(
router=router,
path="/test",
is_websocket=is_websocket,
annotation=Annotated[
List[int],
Depends(
dependency,
use_cache=use_cache,
dependency_scope=main_dependency_scope,
),
],
)
if routing_style == "router":
app.include_router(router)
if use_cache:
expect_correct_amount_of_dependency_activations(
app=app,
urls_and_responses=[
("/test", [1, 1]),
("/test", [1, 1]),
],
dependency_factory=dependency_factory,
expected_activation_times=1,
is_websocket=is_websocket,
)
else:
expect_correct_amount_of_dependency_activations(
app=app,
urls_and_responses=[
("/test", [1, 2]),
("/test", [1, 2]),
],
dependency_factory=dependency_factory,
expected_activation_times=2,
is_websocket=is_websocket,
)
@pytest.mark.parametrize("is_websocket", [True, False], ids=["Websocket", "Endpoint"])
@pytest.mark.parametrize("use_cache", [True, False])
@pytest.mark.parametrize("dependency_style", list(DependencyStyle))
@pytest.mark.parametrize("routing_style", ["app", "router"])
def test_dependency_cache_in_same_endpoint(
dependency_style: DependencyStyle, routing_style, use_cache, is_websocket
):
dependency_factory = DependencyFactory(dependency_style)
depends = Depends(
dependency_factory.get_dependency(),
dependency_scope="lifespan",
use_cache=use_cache,
)
app = FastAPI()
if routing_style == "app":
router = app
else:
router = APIRouter()
async def endpoint_dependency(dependency3: Annotated[int, depends]) -> int:
return dependency3
create_endpoint_3_annotations(
router=router,
path="/test",
is_websocket=is_websocket,
annotation1=Annotated[int, depends],
annotation2=Annotated[int, depends],
annotation3=Annotated[int, Depends(endpoint_dependency)],
)
if routing_style == "router":
app.include_router(router)
if use_cache:
expect_correct_amount_of_dependency_activations(
app=app,
urls_and_responses=[
("/test", [1, 1, 1]),
("/test", [1, 1, 1]),
],
dependency_factory=dependency_factory,
expected_activation_times=1,
is_websocket=is_websocket,
)
else:
expect_correct_amount_of_dependency_activations(
app=app,
urls_and_responses=[
("/test", [1, 2, 3]),
("/test", [1, 2, 3]),
],
dependency_factory=dependency_factory,
expected_activation_times=3,
is_websocket=is_websocket,
)
@pytest.mark.parametrize("is_websocket", [True, False], ids=["Websocket", "Endpoint"])
@pytest.mark.parametrize("use_cache", [True, False])
@pytest.mark.parametrize("dependency_style", list(DependencyStyle))
@pytest.mark.parametrize("routing_style", ["app", "router"])
def test_dependency_cache_in_different_endpoints(
dependency_style: DependencyStyle, routing_style, use_cache, is_websocket
):
dependency_factory = DependencyFactory(dependency_style)
depends = Depends(
dependency_factory.get_dependency(),
dependency_scope="lifespan",
use_cache=use_cache,
)
app = FastAPI()
if routing_style == "app":
router = app
else:
router = APIRouter()
async def endpoint_dependency(dependency3: Annotated[int, depends]) -> int:
return dependency3
create_endpoint_3_annotations(
router=router,
path="/test1",
is_websocket=is_websocket,
annotation1=Annotated[int, depends],
annotation2=Annotated[int, depends],
annotation3=Annotated[int, Depends(endpoint_dependency)],
)
create_endpoint_3_annotations(
router=router,
path="/test2",
is_websocket=is_websocket,
annotation1=Annotated[int, depends],
annotation2=Annotated[int, depends],
annotation3=Annotated[int, Depends(endpoint_dependency)],
)
if routing_style == "router":
app.include_router(router)
if use_cache:
expect_correct_amount_of_dependency_activations(
app=app,
urls_and_responses=[
("/test1", [1, 1, 1]),
("/test2", [1, 1, 1]),
("/test1", [1, 1, 1]),
("/test2", [1, 1, 1]),
],
dependency_factory=dependency_factory,
expected_activation_times=1,
is_websocket=is_websocket,
)
else:
expect_correct_amount_of_dependency_activations(
app=app,
urls_and_responses=[
("/test1", [1, 2, 3]),
("/test2", [4, 5, 3]),
("/test1", [1, 2, 3]),
("/test2", [4, 5, 3]),
],
dependency_factory=dependency_factory,
expected_activation_times=5,
is_websocket=is_websocket,
)
@pytest.mark.parametrize("is_websocket", [True, False], ids=["Websocket", "Endpoint"])
@pytest.mark.parametrize("dependency_style", list(DependencyStyle))
@pytest.mark.parametrize("routing_style", ["app", "router"])
def test_no_cached_dependency(
dependency_style: DependencyStyle,
routing_style,
is_websocket,
):
dependency_factory = DependencyFactory(dependency_style)
depends = Depends(
dependency_factory.get_dependency(),
dependency_scope="lifespan",
use_cache=False,
)
app = FastAPI()
if routing_style == "app":
router = app
else:
router = APIRouter()
create_endpoint_1_annotation(
router=router,
path="/test",
is_websocket=is_websocket,
annotation=Annotated[int, depends],
expected_value=1,
)
if routing_style == "router":
app.include_router(router)
expect_correct_amount_of_dependency_activations(
app=app,
dependency_factory=dependency_factory,
urls_and_responses=[("/test", 1)] * 2,
expected_activation_times=1,
is_websocket=is_websocket,
)
@pytest.mark.parametrize("is_websocket", [True, False], ids=["Websocket", "Endpoint"])
@pytest.mark.parametrize(
"annotation",
[
Annotated[str, Path()],
Annotated[str, Body()],
Annotated[str, Query()],
Annotated[str, Header()],
SecurityScopes,
Annotated[str, Cookie()],
Annotated[str, Form()],
Annotated[str, File()],
BackgroundTasks,
Request,
WebSocket,
],
)
def test_lifespan_scoped_dependency_cannot_use_endpoint_scoped_parameters(
annotation, is_websocket
):
async def dependency_func(param: annotation) -> None:
yield # pragma: nocover
app = FastAPI()
with pytest.raises(DependencyScopeConflict):
create_endpoint_1_annotation(
router=app,
path="/test",
is_websocket=is_websocket,
annotation=Annotated[
None, Depends(dependency_func, dependency_scope="lifespan")
],
)
@pytest.mark.parametrize("is_websocket", [True, False], ids=["Websocket", "Endpoint"])
@pytest.mark.parametrize("dependency_style", list(DependencyStyle))
def test_lifespan_scoped_dependency_can_use_other_lifespan_scoped_dependencies(
dependency_style: DependencyStyle, is_websocket
):
dependency_factory = DependencyFactory(dependency_style)
async def lifespan_scoped_dependency(
param: Annotated[
int,
Depends(dependency_factory.get_dependency(), dependency_scope="lifespan"),
],
) -> AsyncGenerator[int, None]:
yield param
app = FastAPI()
create_endpoint_1_annotation(
router=app,
path="/test",
is_websocket=is_websocket,
annotation=Annotated[int, Depends(lifespan_scoped_dependency)],
expected_value=1,
)
expect_correct_amount_of_dependency_activations(
app=app,
dependency_factory=dependency_factory,
expected_activation_times=1,
urls_and_responses=[("/test", 1)] * 2,
is_websocket=is_websocket,
)
@pytest.mark.parametrize("is_websocket", [True, False], ids=["Websocket", "Endpoint"])
@pytest.mark.parametrize(
["dependency_style", "supports_teardown"],
[
(DependencyStyle.SYNC_FUNCTION, False),
(DependencyStyle.ASYNC_FUNCTION, False),
(DependencyStyle.SYNC_GENERATOR, True),
(DependencyStyle.ASYNC_GENERATOR, True),
],
)
def test_the_same_dependency_can_work_in_different_scopes(
dependency_style: DependencyStyle, supports_teardown, is_websocket
):
dependency_factory = DependencyFactory(dependency_style)
app = FastAPI()
create_endpoint_2_annotations(
router=app,
path="/test",
is_websocket=is_websocket,
annotation1=Annotated[
int,
Depends(dependency_factory.get_dependency(), dependency_scope="endpoint"),
],
annotation2=Annotated[
int,
Depends(dependency_factory.get_dependency(), dependency_scope="lifespan"),
],
)
if is_websocket:
get_response = use_websocket
else:
get_response = use_endpoint
assert dependency_factory.activation_times == 0
assert dependency_factory.deactivation_times == 0
with TestClient(app) as client:
assert dependency_factory.activation_times == 1
assert dependency_factory.deactivation_times == 0
assert get_response(client, "/test") == [2, 1]
assert dependency_factory.activation_times == 2
if supports_teardown:
if is_websocket:
# Websockets teardown might take some time after the test client
# has disconnected
sleep(0.1)
assert dependency_factory.deactivation_times == 1
else:
assert dependency_factory.deactivation_times == 0
assert get_response(client, "/test") == [3, 1]
assert dependency_factory.activation_times == 3
if supports_teardown:
if is_websocket:
# Websockets teardown might take some time after the test client
# has disconnected
sleep(0.1)
assert dependency_factory.deactivation_times == 2
else:
assert dependency_factory.deactivation_times == 0
assert dependency_factory.activation_times == 3
if supports_teardown:
assert dependency_factory.deactivation_times == 3
else:
assert dependency_factory.deactivation_times == 0
@pytest.mark.parametrize(
"lifespan_style", ["lifespan_generator", "events_decorator", "events_constructor"]
)
@pytest.mark.parametrize("is_websocket", [True, False], ids=["Websocket", "Endpoint"])
@pytest.mark.parametrize("dependency_style", list(DependencyStyle))
def test_lifespan_scoped_dependency_can_be_used_alongside_custom_lifespans(
dependency_style: DependencyStyle,
is_websocket,
lifespan_style: Literal["lifespan_function", "lifespan_events"],
):
lifespan_started = False
lifespan_ended = False
if lifespan_style == "lifespan_generator":
@asynccontextmanager
async def lifespan(app: FastAPI) -> AsyncGenerator[Dict[str, int], None]:
nonlocal lifespan_started
nonlocal lifespan_ended
lifespan_started = True
yield
lifespan_ended = True
app = FastAPI(lifespan=lifespan)
elif lifespan_style == "events_decorator":
app = FastAPI()
with warnings.catch_warnings(record=True):
warnings.simplefilter("always")
@app.on_event("startup")
async def startup() -> None:
nonlocal lifespan_started
lifespan_started = True
@app.on_event("shutdown")
async def shutdown() -> None:
nonlocal lifespan_ended
lifespan_ended = True
else:
assert lifespan_style == "events_constructor"
async def startup() -> None:
nonlocal lifespan_started
lifespan_started = True
async def shutdown() -> None:
nonlocal lifespan_ended
lifespan_ended = True
app = FastAPI(on_startup=[startup], on_shutdown=[shutdown])
dependency_factory = DependencyFactory(dependency_style)
create_endpoint_1_annotation(
router=app,
path="/test",
is_websocket=is_websocket,
annotation=Annotated[
int,
Depends(dependency_factory.get_dependency(), dependency_scope="lifespan"),
],
expected_value=1,
)
expect_correct_amount_of_dependency_activations(
app=app,
dependency_factory=dependency_factory,
expected_activation_times=1,
urls_and_responses=[("/test", 1)] * 2,
is_websocket=is_websocket,
)
assert lifespan_started and lifespan_ended
@pytest.mark.parametrize("is_websocket", [True, False], ids=["Websocket", "Endpoint"])
@pytest.mark.parametrize("depends_class", [Depends, Security])
def test_lifespan_scoped_dependency_cannot_use_endpoint_scoped_dependencies(
depends_class, is_websocket
):
async def sub_dependency() -> None:
pass # pragma: nocover
async def dependency_func(
param: Annotated[None, depends_class(sub_dependency)],
) -> None:
pass # pragma: nocover
app = FastAPI()
with pytest.raises(DependencyScopeConflict):
create_endpoint_1_annotation(
router=app,
path="/test",
is_websocket=is_websocket,
annotation=Annotated[
None, Depends(dependency_func, dependency_scope="lifespan")
],
)
@pytest.mark.parametrize("is_websocket", [True, False], ids=["Websocket", "Endpoint"])
@pytest.mark.parametrize("use_cache", [True, False])
@pytest.mark.parametrize("dependency_style", list(DependencyStyle))
@pytest.mark.parametrize("routing_style", ["app_endpoint", "router_endpoint"])
def test_dependencies_must_provide_correct_dependency_scope(
dependency_style: DependencyStyle, routing_style, use_cache, is_websocket
):
dependency_factory = DependencyFactory(dependency_style)
app = FastAPI()
if routing_style == "app_endpoint":
router = app
else:
router = APIRouter()
with pytest.raises(
InvalidDependencyScope,
match=r'Dependency "value" of .* has an invalid scope: ' r'"incorrect"',
):
create_endpoint_1_annotation(
router=router,
path="/test",
is_websocket=is_websocket,
annotation=Annotated[
None,
Depends(
dependency_factory.get_dependency(),
dependency_scope="incorrect",
use_cache=use_cache,
),
],
)
@pytest.mark.parametrize("is_websocket", [True, False], ids=["Websocket", "Endpoint"])
@pytest.mark.parametrize("use_cache", [True, False])
@pytest.mark.parametrize("dependency_style", list(DependencyStyle))
@pytest.mark.parametrize("routing_style", ["app_endpoint", "router_endpoint"])
def test_endpoints_report_incorrect_dependency_scope(
dependency_style: DependencyStyle, routing_style, use_cache, is_websocket
):
dependency_factory = DependencyFactory(dependency_style)
app = FastAPI()
if routing_style == "app_endpoint":
router = app
else:
router = APIRouter()
depends = Depends(
dependency_factory.get_dependency(),
dependency_scope="lifespan",
use_cache=use_cache,
)
# We intentionally change the dependency scope here to bypass the
# validation at the function level.
depends.dependency_scope = "asdad"
with pytest.raises(InvalidDependencyScope):
create_endpoint_1_annotation(
router=router,
path="/test",
is_websocket=is_websocket,
annotation=Annotated[int, depends],
)
@pytest.mark.parametrize("is_websocket", [True, False], ids=["Websocket", "Endpoint"])
@pytest.mark.parametrize("use_cache", [True, False])
@pytest.mark.parametrize("dependency_style", list(DependencyStyle))
@pytest.mark.parametrize("routing_style", ["app", "router"])
def test_endpoints_report_incorrect_dependency_scope_at_router_scope(
dependency_style: DependencyStyle, routing_style, use_cache, is_websocket
):
dependency_factory = DependencyFactory(DependencyStyle.ASYNC_GENERATOR)
depends = Depends(dependency_factory.get_dependency(), dependency_scope="lifespan")
# We intentionally change the dependency scope here to bypass the
# validation at the function level.
depends.dependency_scope = "asdad"
if routing_style == "app":
app = FastAPI(dependencies=[depends])
router = app
else:
router = APIRouter(dependencies=[depends])
with pytest.raises(InvalidDependencyScope):
create_endpoint_0_annotations(
router=router,
path="/test",
is_websocket=is_websocket,
)
@pytest.mark.parametrize("is_websocket", [True, False], ids=["Websocket", "Endpoint"])
@pytest.mark.parametrize("use_cache", [True, False])
@pytest.mark.parametrize("dependency_style", list(DependencyStyle))
@pytest.mark.parametrize("routing_style", ["app_endpoint", "router_endpoint"])
def test_endpoints_report_uninitialized_dependency(
dependency_style: DependencyStyle, routing_style, use_cache, is_websocket
):
dependency_factory = DependencyFactory(dependency_style)
app = FastAPI()
if routing_style == "app_endpoint":
router = app
else:
router = APIRouter()
depends = Depends(
dependency_factory.get_dependency(),
dependency_scope="lifespan",
use_cache=use_cache,
)
create_endpoint_1_annotation(
router=router,
path="/test",
is_websocket=is_websocket,
annotation=Annotated[int, depends],
expected_value=1,
)
if routing_style == "router_endpoint":
app.include_router(router)
with TestClient(app) as client:
dependencies = client.app_state["__fastapi__"]["lifespan_scoped_dependencies"]
client.app_state["__fastapi__"]["lifespan_scoped_dependencies"] = {}
try:
with pytest.raises(UninitializedLifespanDependency):
if is_websocket:
with client.websocket_connect("/test"):
pass # pragma: nocover
else:
client.post("/test")
finally:
client.app_state["__fastapi__"]["lifespan_scoped_dependencies"] = (
dependencies
)
@pytest.mark.parametrize("is_websocket", [True, False], ids=["Websocket", "Endpoint"])
@pytest.mark.parametrize("use_cache", [True, False])
@pytest.mark.parametrize("dependency_style", list(DependencyStyle))
@pytest.mark.parametrize("routing_style", ["app_endpoint", "router_endpoint"])
def test_endpoints_report_uninitialized_internal_lifespan(
dependency_style: DependencyStyle, routing_style, use_cache, is_websocket
):
dependency_factory = DependencyFactory(dependency_style)
app = FastAPI()
if routing_style == "app_endpoint":
router = app
else:
router = APIRouter()
depends = Depends(
dependency_factory.get_dependency(),
dependency_scope="lifespan",
use_cache=use_cache,
)
create_endpoint_1_annotation(
router=router,
path="/test",
is_websocket=is_websocket,
annotation=Annotated[int, depends],
expected_value=1,
)
if routing_style == "router_endpoint":
app.include_router(router)
with TestClient(app) as client:
internal_state = client.app_state["__fastapi__"]
del client.app_state["__fastapi__"]
try:
with pytest.raises(UninitializedLifespanDependency):
if is_websocket:
with client.websocket_connect("/test"):
pass # pragma: nocover
else:
client.post("/test")
finally:
client.app_state["__fastapi__"] = internal_state
@pytest.mark.parametrize("is_websocket", [True, False], ids=["Websocket", "Endpoint"])
@pytest.mark.parametrize("use_cache", [True, False])
@pytest.mark.parametrize("dependency_style", list(DependencyStyle))
@pytest.mark.parametrize("routing_style", ["app_endpoint", "router_endpoint"])
def test_bad_lifespan_scoped_dependencies(
use_cache, dependency_style: DependencyStyle, routing_style, is_websocket
):
dependency_factory = DependencyFactory(dependency_style, should_error=True)
depends = Depends(
dependency_factory.get_dependency(),
dependency_scope="lifespan",
use_cache=use_cache,
)
app = FastAPI()
if routing_style == "app_endpoint":
router = app
else:
router = APIRouter()
create_endpoint_1_annotation(
router=router,
path="/test",
is_websocket=is_websocket,
annotation=Annotated[int, depends],
expected_value=1,
)
if routing_style == "router_endpoint":
app.include_router(router)
with pytest.raises(IntentionallyBadDependency) as exception_info:
with TestClient(app):
pass
assert exception_info.value.args == (1,)
def test_endpoint_dependant_backwards_compatibility():
dependency_factory = DependencyFactory(DependencyStyle.ASYNC_GENERATOR)
def endpoint(
dependency1: Annotated[int, Depends(dependency_factory.get_dependency())],
dependency2: Annotated[
int,
Depends(dependency_factory.get_dependency(), dependency_scope="lifespan"),
],
):
pass # pragma: nocover
dependant = get_endpoint_dependant(
path="/test",
call=endpoint,
name="endpoint",
)
assert dependant.dependencies == tuple(
dependant.lifespan_dependencies + dependant.endpoint_dependencies
)