fix: resolve merge with master — lifespan app vs router

- Default lifespan: use app.router for _DefaultLifespan (router has
  _startup/_shutdown; FastAPI app does not).
- Wrapper: when app is FastAPI, set fastapi_app from app and pass
  app.router to _run_lifespan_dependencies so lifespan deps are collected.
- Test: use only Request.receive() (Starlette Request has no .send).

Made-with: Cursor
This commit is contained in:
essentiaMarco 2026-03-15 16:59:20 -07:00
parent df44ff0d9e
commit 53ebb9b46a
2 changed files with 10 additions and 4 deletions

View File

@ -49,6 +49,11 @@ def _wrap_lifespan_with_dependency_cache(original: Any) -> Any:
@asynccontextmanager
async def cm() -> Any:
fastapi_app = getattr(app, "_fastapi_app", None)
if fastapi_app is None and hasattr(app, "router"):
router = getattr(app, "router", None)
if router is not None and getattr(router, "_fastapi_app", None) is app:
fastapi_app = app
router_for_deps = getattr(app, "router", app)
stack: AsyncExitStack | None = None
orig_cm = original(app)
try:
@ -56,7 +61,9 @@ def _wrap_lifespan_with_dependency_cache(original: Any) -> Any:
stack = AsyncExitStack()
await stack.__aenter__()
cache: dict[Any, Any] = {}
await routing._run_lifespan_dependencies(app, cache, stack)
await routing._run_lifespan_dependencies(
router_for_deps, cache, stack
)
setattr(
fastapi_app.state,
FASTAPI_LIFESPAN_DEPENDENCY_CACHE,
@ -1020,7 +1027,7 @@ class FastAPI(Starlette):
_inner_lifespan = (
lifespan
if lifespan is not None
else (lambda app: routing._DefaultLifespan(app))
else (lambda app: routing._DefaultLifespan(app.router))
)
_lifespan = _wrap_lifespan_with_dependency_cache(_inner_lifespan)
self.router: routing.APIRouter = routing.APIRouter(

View File

@ -122,10 +122,9 @@ def test_collect_lifespan_dependants_route_level_scope() -> None:
def test_lifespan_dependency_synthetic_request_receive_send() -> None:
"""Lifespan dep that uses Request.receive/send covers noop_receive and noop_send during startup."""
"""Lifespan dep that uses Request.receive covers noop_receive during startup."""
async def lifespan_dep(request: Request) -> str:
await request.receive()
await request.send({"type": "http.response.body"})
return "ok"
app = FastAPI()