{"id":1336,"library":"asgi-lifespan","title":"ASGI Lifespan","description":"asgi-lifespan is a Python library that enables programmatic control over the startup and shutdown lifecycle events of ASGI applications. It's primarily used for testing or mocking ASGI apps without requiring a full ASGI server, facilitating resource initialization and cleanup during development and CI. The current version is 2.1.0, with releases typically driven by new features, bug fixes, or Python version support.","status":"active","version":"2.1.0","language":"en","source_language":"en","source_url":"https://github.com/florimondmanca/asgi-lifespan","tags":["asgi","lifespan","testing","async","starlette","fastapi","framework-agnostic"],"install":[{"cmd":"pip install asgi-lifespan","lang":"bash","label":"Install stable version"}],"dependencies":[{"reason":"Requires Python 3.7 or newer.","package":"python","optional":false}],"imports":[{"symbol":"LifespanManager","correct":"from asgi_lifespan import LifespanManager"}],"quickstart":{"code":"import asyncio\nfrom contextlib import asynccontextmanager\nfrom asgi_lifespan import LifespanManager\nfrom starlette.applications import Starlette\nfrom starlette.responses import PlainTextResponse\n\n# An example ASGI application with a lifespan context manager\n@asynccontextmanager\nasync def lifespan(app: Starlette):\n    print(\"ASGI app startup: Initializing resources...\")\n    yield\n    print(\"ASGI app shutdown: Cleaning up resources...\")\n\napp = Starlette(lifespan=lifespan)\n\n@app.route(\"/\")\nasync def homepage(request):\n    return PlainTextResponse(\"Hello, world!\")\n\nasync def run_lifespan_example():\n    print(\"Starting LifespanManager...\")\n    async with LifespanManager(app) as manager:\n        print(\"LifespanManager active, app is ready.\")\n        # In a real test, you would now use an ASGI client like httpx.AsyncClient(app=manager.app)\n        # to send requests and interact with the 'started' application.\n        # For this example, we'll just show the lifespan events.\n    print(\"LifespanManager exited, app is shut down.\")\n\nif __name__ == \"__main__\":\n    asyncio.run(run_lifespan_example())\n","lang":"python","description":"This quickstart demonstrates how to use `LifespanManager` to programmatically trigger the startup and shutdown events of an ASGI application. It defines a simple Starlette app with a lifespan context manager that prints messages. Running this code will execute the startup logic, proceed through the `async with` block, and then execute the shutdown logic, all without needing to spin up a separate ASGI server. This pattern is particularly useful for testing."},"warnings":[{"fix":"Upgrade your Python environment to 3.7 or newer. If not possible, pin `asgi-lifespan<2.0.0`.","message":"Version 2.0.0 of `asgi-lifespan` dropped support for Python 3.6. Users on Python 3.6 must remain on `asgi-lifespan<2.0.0` or upgrade their Python interpreter.","severity":"breaking","affected_versions":">=2.0.0"},{"fix":"Migrate your code to use `LifespanManager` as an asynchronous context manager, as shown in the quickstart example.","message":"The `Lifespan` class and `LifespanMiddleware` were removed in earlier major versions (specifically 1.0.0) in favor of the `LifespanManager` asynchronous context manager. Code using the old API will break.","severity":"breaking","affected_versions":">=1.0.0"},{"fix":"Ensure your ASGI application fully conforms to the ASGI lifespan specification (e.g., sending `lifespan.startup.complete` or `lifespan.shutdown.complete` events). If using an ASGI server like Uvicorn, running with `--lifespan on` might reveal the underlying error during startup/shutdown.","message":"If you encounter the error `LifespanNotSupported` or `ASGI 'lifespan' protocol appears unsupported`, it typically means the wrapped ASGI application did not correctly implement the ASGI lifespan protocol, or an unhandled exception occurred during its startup or shutdown phase. `asgi-lifespan` detects this if the app calls `send()` before `receive()` for the first time, or raises an exception during startup.","severity":"gotcha","affected_versions":"All versions"},{"fix":"Modify your test client initialization to `httpx.AsyncClient(transport=httpx.ASGITransport(app=manager.app))`.","message":"When using `LifespanManager` in conjunction with an ASGI test client (e.g., `httpx.AsyncClient`), it's crucial to pass `manager.app` (not just `app`) to the client's `ASGITransport`. This ensures that any state created by the lifespan events is correctly propagated and available to subsequent request/response handling within the client's scope.","severity":"gotcha","affected_versions":"All versions"}],"env_vars":null,"last_verified":"2026-04-09T00:00:00.000Z","next_check":"2026-07-08T00:00:00.000Z"}