All Projects → florimondmanca → asgi-lifespan

florimondmanca / asgi-lifespan

Licence: MIT license
Programmatic startup/shutdown of ASGI apps.

Programming Languages

python
139335 projects - #7 most used programming language
shell
77523 projects

Labels

Projects that are alternatives of or similar to asgi-lifespan

Uvicorn
The lightning-fast ASGI server. 🦄
Stars: ✭ 4,676 (+4150.91%)
Mutual labels:  asgi
async-asgi-testclient
A framework-agnostic library for testing ASGI web applications
Stars: ✭ 123 (+11.82%)
Mutual labels:  asgi
TikTokDownloader PyWebIO
🚀「Douyin_TikTok_Download_API」是一个开箱即用的高性能异步抖音|TikTok数据爬取工具,支持API调用,在线批量解析及下载。
Stars: ✭ 919 (+735.45%)
Mutual labels:  asgi
Sanic
Async Python 3.7+ web server/framework | Build fast. Run fast.
Stars: ✭ 15,660 (+14136.36%)
Mutual labels:  asgi
asgi-caches
Server-side HTTP caching for ASGI applications, inspired by Django's cache framework
Stars: ✭ 18 (-83.64%)
Mutual labels:  asgi
Spontini
A text-combined-with-graphic music editor for creating professional scores with LilyPond
Stars: ✭ 43 (-60.91%)
Mutual labels:  asgi
webargs-starlette
Declarative request parsing and validation for Starlette with webargs
Stars: ✭ 36 (-67.27%)
Mutual labels:  asgi
django-simple-task
Simple background task for Django 3
Stars: ✭ 88 (-20%)
Mutual labels:  asgi
fastapi-project
FastAPI application without global variables(almost) =)
Stars: ✭ 26 (-76.36%)
Mutual labels:  asgi
asgi-csrf
ASGI middleware for protecting against CSRF attacks
Stars: ✭ 43 (-60.91%)
Mutual labels:  asgi
json-head
JSON microservice for performing HEAD requests
Stars: ✭ 31 (-71.82%)
Mutual labels:  asgi
mongox
Familiar async Python MongoDB ODM
Stars: ✭ 113 (+2.73%)
Mutual labels:  asgi
asgi-babel
Adds internationalization (i18n) support to ASGI applications (Asyncio/Trio)
Stars: ✭ 21 (-80.91%)
Mutual labels:  asgi
Datasette
An open source multi-tool for exploring and publishing data
Stars: ✭ 5,640 (+5027.27%)
Mutual labels:  asgi
a2wsgi
Convert WSGI app to ASGI app or ASGI app to WSGI app.
Stars: ✭ 78 (-29.09%)
Mutual labels:  asgi
starlette-graphene3
An ASGI app for using Graphene v3 with Starlette / FastAPI
Stars: ✭ 52 (-52.73%)
Mutual labels:  asgi
dashboard
An admin interface for ASGI Web frameworks.
Stars: ✭ 120 (+9.09%)
Mutual labels:  asgi
asgi-ratelimit
A ASGI Middleware to rate limit
Stars: ✭ 170 (+54.55%)
Mutual labels:  asgi
livelog
A Django Channels example project to demonstrate the ASGI use case.
Stars: ✭ 20 (-81.82%)
Mutual labels:  asgi
starlite
Light, Flexible and Extensible ASGI API framework
Stars: ✭ 1,525 (+1286.36%)
Mutual labels:  asgi

asgi-lifespan

Build Status Coverage Package version

Programmatically send startup/shutdown lifespan events into ASGI applications. When used in combination with an ASGI-capable HTTP client such as HTTPX, this allows mocking or testing ASGI applications without having to spin up an ASGI server.

Features

  • Send lifespan events to an ASGI app using LifespanManager.
  • Support for asyncio and trio.
  • Fully type-annotated.
  • 100% test coverage.

Installation

pip install 'asgi-lifespan==1.*'

Usage

asgi-lifespan provides a LifespanManager to programmatically send ASGI lifespan events into an ASGI app. This can be used to programmatically startup/shutdown an ASGI app without having to spin up an ASGI server.

LifespanManager can run on either asyncio or trio, and will auto-detect the async library in use.

Basic usage

# example.py
from asgi_lifespan import LifespanManager
from starlette.applications import Starlette

# Example lifespan-capable ASGI app. Any ASGI app that supports
# the lifespan protocol will do, e.g. FastAPI, Quart, Responder, ...
app = Starlette(
    on_startup=[lambda: print("Starting up!")],
    on_shutdown=[lambda: print("Shutting down!")],
)

async def main():
    async with LifespanManager(app):
        print("We're in!")

# On asyncio:
import asyncio; asyncio.run(main())

# On trio:
# import trio; trio.run(main)

Output:

$ python example.py
Starting up!
We're in!
Shutting down!

Sending lifespan events for testing

The example below demonstrates how to use asgi-lifespan in conjunction with HTTPX and pytest in order to send test requests into an ASGI app.

  • Install dependencies:
pip install asgi-lifespan httpx starlette pytest pytest-asyncio
  • Test script:
# test_app.py
import httpx
import pytest
from asgi_lifespan import LifespanManager
from starlette.applications import Starlette
from starlette.responses import PlainTextResponse
from starlette.routing import Route


@pytest.fixture
async def app():
    async def startup():
        print("Starting up")

    async def shutdown():
        print("Shutting down")

    async def home(request):
        return PlainTextResponse("Hello, world!")

    app = Starlette(
        routes=[Route("/", home)],
        on_startup=[startup],
        on_shutdown=[shutdown]
    )

    async with LifespanManager(app):
        print("We're in!")
        yield app


@pytest.fixture
async def client(app):
    async with httpx.AsyncClient(app=app, base_url="http://app.io") as client:
        print("Client is ready")
        yield client


@pytest.mark.asyncio
async def test_home(client):
    print("Testing")
    response = await client.get("/")
    assert response.status_code == 200
    assert response.text == "Hello, world!"
    print("OK")
  • Run the test suite:
$ pytest -s test_app.py
======================= test session starts =======================

test_app.py Starting up
We're in!
Client is ready
Testing
OK
.Shutting down

======================= 1 passed in 0.88s =======================

API Reference

LifespanManager

def __init__(
    self,
    app: Callable,
    startup_timeout: Optional[float] = 5,
    shutdown_timeout: Optional[float] = 5,
)

An asynchronous context manager that starts up an ASGI app on enter and shuts it down on exit.

More precisely:

  • On enter, start a lifespan request to app in the background, then send the lifespan.startup event and wait for the application to send lifespan.startup.complete.
  • On exit, send the lifespan.shutdown event and wait for the application to send lifespan.shutdown.complete.
  • If an exception occurs during startup, shutdown, or in the body of the async with block, it bubbles up and no shutdown is performed.

Example

async with LifespanManager(app):
    # 'app' was started up.
    ...

# 'app' was shut down.

Parameters

  • app (Callable): an ASGI application.
  • startup_timeout (Optional[float], defaults to 5): maximum number of seconds to wait for the application to startup. Use None for no timeout.
  • shutdown_timeout (Optional[float], defaults to 5): maximum number of seconds to wait for the application to shutdown. Use None for no timeout.

Raises

  • LifespanNotSupported: if the application does not seem to support the lifespan protocol. Based on the rationale that if the app supported the lifespan protocol then it would successfully receive the lifespan.startup ASGI event, unsupported lifespan protocol is detected in two situations:
    • The application called send() before calling receive() for the first time.
    • The application raised an exception during startup before making its first call to receive(). For example, this may be because the application failed on a statement such as assert scope["type"] == "http".
  • TimeoutError: if startup or shutdown timed out.
  • Exception: any exception raised by the application (during startup, shutdown, or within the async with body) that does not indicate it does not support the lifespan protocol.

License

MIT

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].