aiohttp-sse
aiohttp-sse provides server-sent events support for aiohttp. It allows building real-time web applications where the server pushes updates to clients over a single HTTP connection. The current version is 2.2.0, and it has a relatively active release cadence with several updates per year, focusing on Python and aiohttp compatibility.
Common errors
-
ModuleNotFoundError: No module named 'aiohttp_sse'
cause The 'aiohttp-sse' package is not installed in the Python environment.fixInstall the package using pip: 'pip install aiohttp-sse'. -
ImportError: cannot import name 'EventSourceResponse' from 'aiohttp_sse'
cause The 'EventSourceResponse' class is not available in the 'aiohttp_sse' module.fixUse 'sse_response' instead: 'from aiohttp_sse import sse_response'. -
AttributeError: 'EventSourceResponse' object has no attribute 'send'
cause The 'EventSourceResponse' object does not have a 'send' method.fixUse 'sse_response' which provides the 'send' method: 'from aiohttp_sse import sse_response'. -
ModuleNotFoundError: No module named 'aiohttp-sse'
cause The `aiohttp-sse` library is not installed in your Python environment or is not accessible on the Python path.fixInstall the library using pip: `pip install aiohttp-sse` -
AttributeError: module 'aiohttp' has no attribute 'ClientSession'
cause This typically occurs when you have a file named `aiohttp.py` in your project directory, which shadows the actual `aiohttp` library, or if you are trying to use an outdated API for `aiohttp` client requests.fixRename any local file named `aiohttp.py` to something else (e.g., `my_aiohttp_app.py`). Ensure you are using `aiohttp.ClientSession()` for client requests, as direct `aiohttp.get()` was deprecated.
Warnings
- breaking Python version support has been frequently dropped in major and minor releases. Version 2.2.0 dropped Python 3.7, and 2.1.0 dropped Python 3.6 support. Ensure your Python environment meets the `>=3.8` requirement for current versions.
- breaking Major versions of `aiohttp-sse` are tied to specific `aiohttp` versions. Version 2.0.0 introduced compatibility with `aiohttp 3.0+`, while older versions like 1.0.0 required `aiohttp2+`, and 0.1.0 was for `aiohttp<2.0`. Mismatched `aiohttp` versions can lead to runtime errors.
- gotcha Browsers keep the tab's loading spinner active as long as an SSE connection remains open, which can be confusing for users.
- gotcha Prior to v2.2.0, specifically on Python 3.11+, the `EventSourceResponse.wait()` method could swallow user cancellation, making it difficult to gracefully shut down SSE streams.
- gotcha `aiohttp` itself does not natively provide client-side Server-Sent Events parsing. Users attempting to consume `aiohttp-sse` streams with a plain `aiohttp.ClientSession` might find parsing challenging.
- gotcha Web browsers often impose a limit (e.g., 6) on the number of concurrent HTTP connections to a single domain. Exceeding this limit with multiple SSE connections can cause new requests to hang or time out.
Install
-
pip install aiohttp-sse
Imports
- sse_response
from aiohttp_sse import sse_response
- EventSourceResponse
from aiohttp_sse import EventSourceResponse
Quickstart
import asyncio
import json
from datetime import datetime
from aiohttp import web
from aiohttp_sse import sse_response
async def hello(request: web.Request) -> web.StreamResponse:
async with sse_response(request) as resp:
# Optional: send an initial comment to stop browser loading spinner
await resp.send(None, event='comment', data='connected')
while resp.is_connected():
time_dict = {"time": f"Server Time : {datetime.now()}"}
data = json.dumps(time_dict, indent=2)
print(data)
await resp.send(data)
await asyncio.sleep(1)
return resp
async def index(_request: web.Request) -> web.Response:
html = """
<html>
<body>
<script>
var eventSource = new EventSource("/hello");
eventSource.addEventListener("message", event => {
document.getElementById("response").innerText = event.data;
});
</script>
<h1>Response from server:</h1>
<div id="response"></div>
</body>
</html>
"""
return web.Response(text=html, content_type="text/html")
app = web.Application()
app.router.add_route("GET", "/hello", hello)
app.router.add_route("GET", "/", index)
if __name__ == '__main__':
web.run_app(app, host="127.0.0.1", port=8080)