From 8b2028cb25d2fc9f245ef871f30ea12e4b8dde78 Mon Sep 17 00:00:00 2001 From: essentiaMarco <131397104+essentiaMarco@users.noreply.github.com> Date: Sun, 15 Mar 2026 17:05:37 -0700 Subject: [PATCH] fix: normalize lifespan (async/sync gen) before wrapper so router_events tests pass - In FastAPI.__init__, when lifespan is an async or sync generator function, convert to context manager (asynccontextmanager / _wrap_gen_lifespan_context) before _wrap_lifespan_with_dependency_cache so orig_cm has __aenter__/__aexit__. Made-with: Cursor --- fastapi/applications.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/fastapi/applications.py b/fastapi/applications.py index c7328087f4..eb32dde142 100644 --- a/fastapi/applications.py +++ b/fastapi/applications.py @@ -1,3 +1,4 @@ +import inspect from collections.abc import Awaitable, Callable, Coroutine, Sequence from contextlib import AsyncExitStack, asynccontextmanager from enum import Enum @@ -1024,11 +1025,14 @@ class FastAPI(Starlette): """ ), ] = {} - _inner_lifespan = ( - lifespan - if lifespan is not None - else (lambda app: routing._DefaultLifespan(app.router)) - ) + if lifespan is None: + _inner_lifespan = lambda app: routing._DefaultLifespan(app.router) + elif inspect.isasyncgenfunction(lifespan): + _inner_lifespan = asynccontextmanager(lifespan) + elif inspect.isgeneratorfunction(lifespan): + _inner_lifespan = routing._wrap_gen_lifespan_context(lifespan) + else: + _inner_lifespan = lifespan _lifespan = _wrap_lifespan_with_dependency_cache(_inner_lifespan) self.router: routing.APIRouter = routing.APIRouter( routes=routes,