Add native server-sent events support via `client.sse()`

Merged
KL
4mo ago
+529-0

Adds native server-sent events support, so the client has a first-class method for SSE instead of needing a companion library.

API

with httpx2.Client() as client:
    with client.sse("http://localhost:8000/sse") as source:
        for event in source:
            print(event.event, event.data, event.json())
  • Client.sse() / AsyncClient.sse() - same name on both clients (like stream), url-first with method="GET" default. A context manager yielding an EventSource.
  • EventSource - iterate it directly (for event in source / async for event in source) to get ServerSentEvent instances; source.response exposes the underlying Response.
  • ServerSentEvent - frozen dataclass with event, data, id, retry: int | None, and .json().
  • SSEError(TransportError) - raised when the response Content-Type is not text/event-stream.

The method sets Accept: text/event-stream and Cache-Control: no-store (user-supplied headers win), and is built on top of client.stream().

Notes

  • Always-on, no extra and no third-party dependency - the parser is implemented over response.iter_text().
  • Uses a spec-compliant line splitter (\r\n / \r / \n only) rather than iter_lines(), which over-splits on exotic Unicode separators that SSE treats as data.
  • New tests/httpx2/test_sse.py covers parsing, multi-line data, comments, id/retry/null handling, last-event-id persistence, content-type validation, header defaults/override, POST, and chunk-boundary/CRLF splitting (sync + async). _sse.py is at 100% coverage.

AI Disclaimer

This PR was developed with the assistance of either Claude or Codex. I've reviewed and verified the changes.