diff --git a/fastapi/applications.py b/fastapi/applications.py index 7da120a34..adaaebb07 100644 --- a/fastapi/applications.py +++ b/fastapi/applications.py @@ -938,10 +938,7 @@ class FastAPI(Starlette): if lifespan is None: lifespan = FastAPI._internal_lifespan else: - lifespan = merge_lifespan_context( - FastAPI._internal_lifespan, - lifespan - ) + lifespan = merge_lifespan_context(FastAPI._internal_lifespan, lifespan) # Since we always use a lifespan, starlette will no longer run event # handlers which are defined in the scope of the application. @@ -990,8 +987,7 @@ class FastAPI(Starlette): async def _internal_lifespan(self) -> AsyncGenerator[Dict[str, Any], None]: async with AsyncExitStack() as exit_stack: lifespan_scoped_dependencies = await resolve_lifespan_dependants( - app=self, - async_exit_stack=exit_stack + app=self, async_exit_stack=exit_stack ) try: for handler in self._on_startup: @@ -1011,7 +1007,6 @@ class FastAPI(Starlette): else: await run_in_threadpool(handler) - def openapi(self) -> Dict[str, Any]: """ Generate the OpenAPI schema of the application. This is called by FastAPI @@ -4541,12 +4536,14 @@ class FastAPI(Starlette): Read more about it in the [FastAPI docs for Lifespan Events](https://fastapi.tiangolo.com/advanced/events/#alternative-events-deprecated). """ + def decorator(func: DecoratedCallable) -> DecoratedCallable: if event_type == "startup": self._on_startup.append(func) else: self._on_shutdown.append(func) return func + return decorator def middleware( diff --git a/fastapi/dependencies/models.py b/fastapi/dependencies/models.py index b68f0339c..2ea813d48 100644 --- a/fastapi/dependencies/models.py +++ b/fastapi/dependencies/models.py @@ -36,7 +36,10 @@ class LifespanDependant: self.cache_key = (self.caller, self.index) -EndpointDependantCacheKey: TypeAlias = Tuple[Optional[Callable[..., Any]], Tuple[str, ...]] +EndpointDependantCacheKey: TypeAlias = Tuple[ + Optional[Callable[..., Any]], Tuple[str, ...] +] + @dataclass class EndpointDependant: @@ -80,6 +83,7 @@ class EndpointDependant: return tuple(lifespan_dependencies + endpoint_dependencies) + # Kept for backwards compatibility Dependant = EndpointDependant CacheKey: TypeAlias = Union[EndpointDependantCacheKey, LifespanDependantCacheKey] diff --git a/fastapi/dependencies/utils.py b/fastapi/dependencies/utils.py index df89aad77..96f4a910f 100644 --- a/fastapi/dependencies/utils.py +++ b/fastapi/dependencies/utils.py @@ -357,7 +357,6 @@ def get_lifespan_dependant( return dependant - def get_endpoint_dependant( *, path: str, @@ -678,7 +677,9 @@ async def solve_lifespan_dependant( *, dependant: LifespanDependant, dependency_overrides_provider: Optional[Any] = None, - dependency_cache: Optional[Dict[LifespanDependantCacheKey, Callable[..., Any]]] = None, + dependency_cache: Optional[ + Dict[LifespanDependantCacheKey, Callable[..., Any]] + ] = None, async_exit_stack: AsyncExitStack, ) -> SolvedLifespanDependant: dependency_cache = dependency_cache or {} diff --git a/fastapi/lifespan.py b/fastapi/lifespan.py index d725a5e30..9b8afba03 100644 --- a/fastapi/lifespan.py +++ b/fastapi/lifespan.py @@ -27,9 +27,7 @@ def _get_lifespan_dependants(app: FastAPI) -> List[LifespanDependant]: async def resolve_lifespan_dependants( - *, - app: FastAPI, - async_exit_stack: AsyncExitStack + *, app: FastAPI, async_exit_stack: AsyncExitStack ) -> Dict[LifespanDependantCacheKey, Callable[..., Any]]: lifespan_dependants = _get_lifespan_dependants(app) dependency_cache: Dict[LifespanDependantCacheKey, Callable[..., Any]] = {} @@ -38,7 +36,7 @@ async def resolve_lifespan_dependants( dependant=lifespan_dependant, dependency_overrides_provider=app, dependency_cache=dependency_cache, - async_exit_stack=async_exit_stack + async_exit_stack=async_exit_stack, ) dependency_cache.update(solved_dependency.dependency_cache) diff --git a/fastapi/param_functions.py b/fastapi/param_functions.py index e9a15c166..4112e90e2 100644 --- a/fastapi/param_functions.py +++ b/fastapi/param_functions.py @@ -2272,8 +2272,8 @@ def Depends( # noqa: N802 or any other annotation which does not make sense in a scope of an application's entire lifespan. """ - ) - ] = "endpoint" + ), + ] = "endpoint", ) -> Any: """ Declare a FastAPI dependency. @@ -2304,7 +2304,9 @@ def Depends( # noqa: N802 return commons ``` """ - return params.Depends(dependency=dependency, use_cache=use_cache, dependency_scope=dependency_scope) + return params.Depends( + dependency=dependency, use_cache=use_cache, dependency_scope=dependency_scope + ) def Security( # noqa: N802 diff --git a/fastapi/params.py b/fastapi/params.py index f655acba8..954d4b27d 100644 --- a/fastapi/params.py +++ b/fastapi/params.py @@ -764,7 +764,7 @@ class Depends: dependency: Optional[Callable[..., Any]] = None, *, use_cache: bool = True, - dependency_scope: DependencyScope = "endpoint" + dependency_scope: DependencyScope = "endpoint", ): self.dependency = dependency self.use_cache = use_cache @@ -776,7 +776,7 @@ class Depends: if self.dependency_scope == "endpoint": dependency_scope = "" else: - dependency_scope = f", dependency_scope=\"{self.dependency_scope}\"" + dependency_scope = f', dependency_scope="{self.dependency_scope}"' return f"{self.__class__.__name__}({attr}{cache}{dependency_scope})" @@ -790,8 +790,6 @@ class Security(Depends): use_cache: bool = True, ): super().__init__( - dependency=dependency, - use_cache=use_cache, - dependency_scope="endpoint" + dependency=dependency, use_cache=use_cache, dependency_scope="endpoint" ) self.scopes = scopes or [] diff --git a/tests/test_lifespan_scoped_dependencies.py b/tests/test_lifespan_scoped_dependencies.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/test_params_repr.py b/tests/test_params_repr.py index 10f044888..8921026b2 100644 --- a/tests/test_params_repr.py +++ b/tests/test_params_repr.py @@ -144,16 +144,30 @@ def test_body_repr_list(): assert repr(Body([])) == "Body([])" -@pytest.mark.parametrize(["depends", "expected_repr"], [ - [Depends(), "Depends(NoneType)"], - [Depends(get_user), "Depends(get_user)"], - [Depends(use_cache=False), "Depends(NoneType, use_cache=False)"], - [Depends(get_user, use_cache=False), "Depends(get_user, use_cache=False)"], - - [Depends(dependency_scope="lifespan"), "Depends(NoneType, dependency_scope=\"lifespan\")"], - [Depends(get_user, dependency_scope="lifespan"), "Depends(get_user, dependency_scope=\"lifespan\")"], - [Depends(use_cache=False, dependency_scope="lifespan"), "Depends(NoneType, use_cache=False, dependency_scope=\"lifespan\")"], - [Depends(get_user, use_cache=False, dependency_scope="lifespan"), "Depends(get_user, use_cache=False, dependency_scope=\"lifespan\")"], -]) +@pytest.mark.parametrize( + ["depends", "expected_repr"], + [ + [Depends(), "Depends(NoneType)"], + [Depends(get_user), "Depends(get_user)"], + [Depends(use_cache=False), "Depends(NoneType, use_cache=False)"], + [Depends(get_user, use_cache=False), "Depends(get_user, use_cache=False)"], + [ + Depends(dependency_scope="lifespan"), + 'Depends(NoneType, dependency_scope="lifespan")', + ], + [ + Depends(get_user, dependency_scope="lifespan"), + 'Depends(get_user, dependency_scope="lifespan")', + ], + [ + Depends(use_cache=False, dependency_scope="lifespan"), + 'Depends(NoneType, use_cache=False, dependency_scope="lifespan")', + ], + [ + Depends(get_user, use_cache=False, dependency_scope="lifespan"), + 'Depends(get_user, use_cache=False, dependency_scope="lifespan")', + ], + ], +) def test_depends_repr(depends, expected_repr): assert repr(depends) == expected_repr diff --git a/tests/test_router_events.py b/tests/test_router_events.py index 8289a7301..2f110e684 100644 --- a/tests/test_router_events.py +++ b/tests/test_router_events.py @@ -199,9 +199,7 @@ def test_router_nested_lifespan_state_overriding_by_parent() -> None: "app_specific": True, "router_specific": True, "overridden": "app", - "__fastapi__": { - "lifespan_scoped_dependencies": {} - }, + "__fastapi__": {"lifespan_scoped_dependencies": {}}, } @@ -219,11 +217,7 @@ def test_merged_no_return_lifespans_return_none() -> None: app.include_router(router) with TestClient(app) as client: - assert client.app_state == { - "__fastapi__": { - "lifespan_scoped_dependencies": {} - } - } + assert client.app_state == {"__fastapi__": {"lifespan_scoped_dependencies": {}}} def test_merged_mixed_state_lifespans() -> None: @@ -248,7 +242,5 @@ def test_merged_mixed_state_lifespans() -> None: with TestClient(app) as client: assert client.app_state == { "router": True, - "__fastapi__": { - "lifespan_scoped_dependencies": {} - } + "__fastapi__": {"lifespan_scoped_dependencies": {}}, }