Skip to content

Lifespan and request.state question #33

@prathamlahoti123

Description

@prathamlahoti123

Hi @Kludex. Big thanks for such a comprehensive resource on using FastAPI. I've got a question ragarding to the 5th and 6th tips:
is there a way to get access to request.state objects without calling asgi-lifespan's LifespanManager during testing? Here's a minimal example:

api.py:

from collections.abc import AsyncIterator
from contextlib import asynccontextmanager

from fastapi import FastAPI, Request
from httpx import AsyncClient


@asynccontextmanager
async def lifespan(_: FastAPI) -> AsyncIterator[dict[str, AsyncClient]]:
  async with AsyncClient() as client:
    yield {"client": client}


app = FastAPI(lifespan=lifespan)


@app.get("/test")
async def test(request: Request) -> dict[str, bool]:
  client = request.state.client
  return {"result": isinstance(client, AsyncClient)}

test.py

from collections.abc import AsyncIterator  # noqa: I001

import pytest

# from asgi_lifespan import LifespanManager
from httpx import ASGITransport, AsyncClient

from api import app


@pytest.fixture(scope="session")
def anyio_backend() -> str:
  return "asyncio"


@pytest.fixture(scope="session")
async def client() -> AsyncIterator[AsyncClient]:
  # async with LifespanManager(app) as manager:
  transport = ASGITransport(app)
  async with AsyncClient(base_url="http://test", transport=transport) as ac:
    yield ac


@pytest.mark.anyio
async def test(client: AsyncClient) -> None:
  with pytest.raises(AttributeError) as e:
    resp = await client.get("/test")
  assert "'State' object has no attribute 'client'" in str(e.value)

As a result, the test passes, indicating that the State object has no attribute client, though we declared it in the lifespan. However, if we uncomment LifespanManager and replace app by manager.app when defining the transport object, the test will fail (as expected), because this time the client object is in the application's state.

It's worth mentioning that this problem doesn't appear when we declare state's objects in the old way like app.state.client = client in the lifespan and it doesn't require using asgi-lifespan's LifespanManager.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions