Skip to content

without_asgi

without adapters that turn an ASGI app's receive/send into typed event streams and back.

without_asgi

HttpHandler

HttpHandler = Processor[Inbound, Outbound]

HttpRouter

HttpRouter = Callable[[T, HttpScope], HttpHandler]

Lifespan

WebsocketHandler

WebsocketRouter

WebsocketRouter = Callable[
    [T, WebsocketScope], WebsocketHandler
]

Inbound

Inbound = RequestBody | Disconnect

LifespanEvent

LifespanEvent = Startup | Shutdown

WebsocketInbound

LifespanReply

ConnectionScope

ConnectionScope = HttpScope | WebsocketScope

Scope

ASGIApp

ASGIApp = Callable[
    [RawScope, Receive, Send], Awaitable[None]
]

RawHeaders

RawHeaders = tuple[tuple[bytes, bytes], ...]

RawMessage

RawMessage = Mapping[str, object]

RawScope

RawScope = Mapping[str, object]

Receive

Receive = Callable[[], Awaitable[RawMessage]]

Send

Send = Callable[[RawMessage], Awaitable[None]]

WebsocketData

WebsocketData = WebsocketText | WebsocketBinary

Disconnect dataclass

Disconnect()

The client went away before the request finished.

RequestBody dataclass

RequestBody(body: bytes, more_body: bool)

body instance-attribute

body: bytes

more_body instance-attribute

more_body: bool

Shutdown dataclass

Shutdown()

Startup dataclass

Startup()

WebsocketConnect dataclass

WebsocketConnect()

The client is opening a websocket and awaiting an accept or a close.

WebsocketDisconnect dataclass

WebsocketDisconnect(code: int, reason: str)

code instance-attribute

code: int

reason instance-attribute

reason: str

WebsocketReceive dataclass

WebsocketReceive(data: WebsocketData)

data instance-attribute

EarlyHint dataclass

EarlyHint(links: tuple[bytes, ...])

A 103 Early Hints informational response (http.response.early_hint extension).

links: tuple[bytes, ...]

PathSend dataclass

PathSend(path: str)

Offload sending a file by absolute path (http.response.pathsend extension).

path instance-attribute

path: str

Response dataclass

Response(
    status: int, headers: RawHeaders = (), body: bytes = b""
)

A whole response as one value, the common case behind the event pair.

status instance-attribute

status: int

headers class-attribute instance-attribute

headers: RawHeaders = ()

body class-attribute instance-attribute

body: bytes = b''

ResponseBody dataclass

ResponseBody(body: bytes = b'', more_body: bool = False)

body class-attribute instance-attribute

body: bytes = b''

more_body class-attribute instance-attribute

more_body: bool = False

ResponseDebug dataclass

ResponseDebug(info: Mapping[str, object])

Debug information sent before the response start (http.response.debug extension).

info instance-attribute

info: Mapping[str, object]

ResponseStart dataclass

ResponseStart(
    status: int,
    headers: RawHeaders = (),
    trailers: bool = False,
)

status instance-attribute

status: int

headers class-attribute instance-attribute

headers: RawHeaders = ()

trailers class-attribute instance-attribute

trailers: bool = False

Whether the app will send a ResponseTrailers after the body; requires the http.response.trailers extension.

ResponseTrailers dataclass

ResponseTrailers(
    headers: RawHeaders, more_trailers: bool = False
)

Trailing headers sent after the final body (http.response.trailers extension).

headers instance-attribute

headers: RawHeaders

more_trailers class-attribute instance-attribute

more_trailers: bool = False

ServerPush dataclass

ServerPush(path: str, headers: RawHeaders)

An HTTP/2 server push (http.response.push extension).

path instance-attribute

path: str

headers instance-attribute

headers: RawHeaders

ShutdownComplete dataclass

ShutdownComplete()

ShutdownFailed dataclass

ShutdownFailed(message: str = '')

message class-attribute instance-attribute

message: str = ''

StartupComplete dataclass

StartupComplete()

StartupFailed dataclass

StartupFailed(message: str = '')

message class-attribute instance-attribute

message: str = ''

SupportsFileno

Bases: Protocol

An opened file object backed by a real OS file descriptor (for os.sendfile).

fileno

fileno() -> int

WebsocketAccept dataclass

WebsocketAccept(
    subprotocol: str | None = None, headers: RawHeaders = ()
)

subprotocol class-attribute instance-attribute

subprotocol: str | None = None

headers class-attribute instance-attribute

headers: RawHeaders = ()

WebsocketClose dataclass

WebsocketClose(code: int = 1000, reason: str = '')

Close a websocket connection, or reject it when sent before WebsocketAccept.

code is a WebSocket close code; 1000 is a normal closure. If sent before the handshake is accepted, the server discards code/reason and returns an HTTP 403 instead, so these only reach the client on a close after accept.

code class-attribute instance-attribute

code: int = 1000

reason class-attribute instance-attribute

reason: str = ''

WebsocketResponseBody dataclass

WebsocketResponseBody(
    body: bytes = b"", more_body: bool = False
)

A body chunk of an HTTP denial response (websocket.http.response extension).

body class-attribute instance-attribute

body: bytes = b''

more_body class-attribute instance-attribute

more_body: bool = False

WebsocketResponseStart dataclass

WebsocketResponseStart(
    status: int, headers: RawHeaders = ()
)

The start of an HTTP denial response (websocket.http.response extension).

status instance-attribute

status: int

headers class-attribute instance-attribute

headers: RawHeaders = ()

WebsocketSend dataclass

WebsocketSend(data: WebsocketData)

data instance-attribute

ZeroCopySend dataclass

ZeroCopySend(
    file: SupportsFileno,
    offset: int | None = None,
    count: int | None = None,
    more_body: bool = False,
)

A zero-copy file-descriptor send (http.response.zerocopysend extension).

The application is responsible for closing file afterwards.

file instance-attribute

offset class-attribute instance-attribute

offset: int | None = None

count class-attribute instance-attribute

count: int | None = None

more_body class-attribute instance-attribute

more_body: bool = False

Asgi dataclass

Asgi(version: str, spec_version: str)

The ASGI version metadata carried on every scope's asgi key.

version instance-attribute

version: str

Version of the ASGI spec.

spec_version instance-attribute

spec_version: str

Version of the ASGI sub-spec this server implements.

HttpScope dataclass

HttpScope(
    asgi: Asgi,
    http_version: str,
    method: str,
    scheme: str,
    path: str,
    raw_path: bytes | None,
    query_string: bytes,
    root_path: str,
    headers: RawHeaders,
    client: tuple[str, int] | None,
    server: tuple[str, int | None] | None,
    extensions: Mapping[str, Mapping[str, object]] | None,
)

The per-request connection facts, known once when the request opens.

Field descriptions are taken from the ASGI HTTP connection scope: https://asgi.readthedocs.io/en/latest/specs/www.html#http-connection-scope

The ASGI state namespace is intentionally not surfaced: without threads lifespan-derived state to handlers explicitly through make_asgi_app, rather than reading it from the scope.

asgi instance-attribute

asgi: Asgi

Version metadata for the ASGI spec and HTTP sub-spec.

http_version instance-attribute

http_version: str

One of "1.0", "1.1" or "2".

method instance-attribute

method: str

The HTTP method name, uppercased.

scheme instance-attribute

scheme: str

URL scheme portion (likely "http" or "https"); defaults to "http".

path instance-attribute

path: str

HTTP request target excluding any query string, with percent-encoded sequences and UTF-8 byte sequences decoded into characters.

raw_path instance-attribute

raw_path: bytes | None

The original HTTP path component as the bytes the web server received, excluding any query string; None if the server cannot provide it.

query_string instance-attribute

query_string: bytes

URL portion after the ?, percent-encoded.

root_path instance-attribute

root_path: str

The root path this application is mounted at (WSGI SCRIPT_NAME); defaults to "".

headers instance-attribute

headers: RawHeaders

[name, value] byte-string header pairs, in the order received; duplicates are preserved.

client instance-attribute

client: tuple[str, int] | None

Remote [host, port]; None if not provided.

server instance-attribute

server: tuple[str, int | None] | None

Server [host, port], or [path, None] for a unix socket; None if not provided.

extensions instance-attribute

extensions: Mapping[str, Mapping[str, object]] | None

Server-advertised optional extensions, keyed by name; None if the server advertised none. See parse_tls for reading the tls extension.

LifespanScope dataclass

LifespanScope(asgi: Asgi)

The server lifecycle scope, shared across the whole event loop.

Field descriptions are taken from the ASGI lifespan scope: https://asgi.readthedocs.io/en/latest/specs/lifespan.html#scope

The ASGI state namespace is intentionally not surfaced: without threads lifespan-derived state to handlers explicitly through make_asgi_app (which holds it in a _Cell and passes it per request), rather than via the scope.

asgi instance-attribute

asgi: Asgi

Version metadata for the ASGI spec and lifespan sub-spec.

Tls dataclass

Tls(
    server_cert: str | None,
    client_cert_chain: tuple[str, ...],
    client_cert_name: str | None,
    client_cert_error: str | None,
    tls_version: int | None,
    cipher_suite: int | None,
)

The tls extension's connection info, present only on TLS connections.

Field descriptions are taken from the ASGI TLS extension: https://asgi.readthedocs.io/en/latest/specs/tls.html

server_cert instance-attribute

server_cert: str | None

PEM-encoded server certificate; None if the server cannot provide it.

client_cert_chain instance-attribute

client_cert_chain: tuple[str, ...]

PEM-encoded client certificate chain (client cert first); empty if none.

client_cert_name instance-attribute

client_cert_name: str | None

RFC4514 Distinguished Name of the client certificate subject; None if no client certificate.

client_cert_error instance-attribute

client_cert_error: str | None

Verification error message if a client certificate failed validation; None if it verified or none was provided.

tls_version instance-attribute

tls_version: int | None

TLS version number (e.g. 0x0304 for TLS 1.3); None if not in use.

cipher_suite instance-attribute

cipher_suite: int | None

16-bit cipher suite identifier in network byte order; None if not provided.

WebsocketScope dataclass

WebsocketScope(
    asgi: Asgi,
    http_version: str,
    scheme: str,
    path: str,
    raw_path: bytes | None,
    query_string: bytes,
    root_path: str,
    headers: RawHeaders,
    client: tuple[str, int] | None,
    server: tuple[str, int | None] | None,
    subprotocols: tuple[str, ...],
    extensions: Mapping[str, Mapping[str, object]] | None,
)

The handshake facts of a websocket connection, known when it opens.

Field descriptions are taken from the ASGI WebSocket connection scope: https://asgi.readthedocs.io/en/latest/specs/www.html#websocket-connection-scope

The ASGI state namespace is intentionally not surfaced: without threads lifespan-derived state to handlers explicitly through make_asgi_app, rather than reading it from the scope.

asgi instance-attribute

asgi: Asgi

Version metadata for the ASGI spec and WebSocket sub-spec.

http_version instance-attribute

http_version: str

One of "1.1" or "2"; defaults to "1.1".

scheme instance-attribute

scheme: str

URL scheme portion (likely "ws" or "wss"); defaults to "ws".

path instance-attribute

path: str

HTTP request target excluding any query string, with percent-encoded sequences and UTF-8 byte sequences decoded into characters.

raw_path instance-attribute

raw_path: bytes | None

The original HTTP path component as the bytes the web server received, excluding any query string; None if the server cannot provide it.

query_string instance-attribute

query_string: bytes

URL portion after the ?; defaults to empty.

root_path instance-attribute

root_path: str

The root path this application is mounted at (WSGI SCRIPT_NAME); defaults to "".

headers instance-attribute

headers: RawHeaders

[name, value] byte-string header pairs, in the order received; duplicates are preserved.

client instance-attribute

client: tuple[str, int] | None

Remote [host, port]; None if not provided.

server instance-attribute

server: tuple[str, int | None] | None

Server [host, port], or [path, None] for a unix socket; None if not provided.

subprotocols instance-attribute

subprotocols: tuple[str, ...]

Subprotocols the client advertised; defaults to empty.

extensions instance-attribute

extensions: Mapping[str, Mapping[str, object]] | None

Server-advertised optional extensions, keyed by name; None if the server advertised none. See parse_tls for reading the tls extension.

ClientDisconnect

Bases: Exception

The client disconnected before its request body was fully received.

WebsocketBinary dataclass

WebsocketBinary(data: bytes)

data instance-attribute

data: bytes

WebsocketText dataclass

WebsocketText(text: str)

text instance-attribute

text: str

make_asgi_app

make_asgi_app(
    lifespan: Lifespan[T],
    http: HttpRouter[T] = refuse_http,
    websocket: WebsocketRouter[T] = refuse_websocket,
) -> ASGIApp

Build the ASGI app that drives lifespan and runs a per-connection Processor over each connection's event stream.

This is the ASGI entrypoint: it parses each raw scope into its typed value and owns all the receive/send wiring. The lifespan scope is set up once on startup and torn down on shutdown, with boot failures reported as lifespan.startup.failed / lifespan.shutdown.failed. For a connection scope it calls the matching handler with the state threaded in, wraps receive into the inbound event stream, runs the returned Processor, and drains its outbound stream into send: the handler only ever sees streams.

Each protocol's router defaults to one that refuses the connection, so an app serves a protocol only by passing its own router (an HTTP-only app passes http, a WebSocket-only app passes websocket). The default refusal never reaches app code: an HTTP scope gets a 501 Not Implemented response, a WebSocket scope is closed before accept (which the server turns into a 403). Drilling under this driver, e.g. to build a handler that needs the raw receive/send, is parse_scope plus the http_inbound / http_outbound (and websocket) shell functions this wires together.

refuse_http

refuse_http(state: object, head: HttpScope) -> HttpHandler

An HttpRouter that refuses every request with 501 Not Implemented.

refuse_websocket

refuse_websocket(
    state: object, head: WebsocketScope
) -> WebsocketHandler

A WebsocketRouter that refuses every connection by closing before accept (a 403).

encode_inbound

encode_inbound(event: Inbound) -> RawMessage

Render one inbound http event as the raw dict an ASGI receive returns.

The server-direction dual of parse_inbound: a transport that owns the wire (without-http) builds typed Inbound events and hands them to the app as the dicts ASGI receive yields.

encode_lifespan_event

encode_lifespan_event(event: LifespanEvent) -> RawMessage

Render one lifespan event as the raw dict an ASGI receive returns.

encode_websocket_inbound

encode_websocket_inbound(
    event: WebsocketInbound,
) -> RawMessage

Render one inbound websocket event as the raw dict an ASGI receive returns.

parse_inbound

parse_inbound(message: RawMessage) -> Inbound

Classify one inbound http event. An unknown event is a protocol fault, so it raises.

parse_lifespan_event

parse_lifespan_event(message: RawMessage) -> LifespanEvent

Classify one lifespan event. An unknown event is a protocol fault, so it raises.

parse_websocket_inbound

parse_websocket_inbound(
    message: RawMessage,
) -> WebsocketInbound

Classify one inbound websocket event. An unknown event is a protocol fault, so it raises.

encode_lifespan_reply

encode_lifespan_reply(reply: LifespanReply) -> RawMessage

Render one lifespan reply as the raw dict an ASGI send expects.

encode_outbound

encode_outbound(event: Outbound) -> RawMessage

Render one outbound http event as the raw dict an ASGI send expects.

encode_response

encode_response(response: Response) -> tuple[Outbound, ...]

Split a whole Response into its ResponseStart then final ResponseBody.

encode_websocket_outbound

encode_websocket_outbound(
    event: WebsocketOutbound,
) -> RawMessage

Render one outbound websocket event as the raw dict an ASGI send expects.

parse_lifespan_reply

parse_lifespan_reply(message: RawMessage) -> LifespanReply

Classify one lifespan reply from the raw dict an app passed to send.

parse_outbound

parse_outbound(message: RawMessage) -> Outbound

Classify one outbound http event from the raw dict an app passed to send.

The server-direction dual of encode_outbound: a transport that owns the wire (without-http) reads the dicts the app sends and parses them into typed Outbound events at the boundary. An unknown event is a protocol fault, so it raises.

parse_websocket_outbound

parse_websocket_outbound(
    message: RawMessage,
) -> WebsocketOutbound

Classify one outbound websocket event from the raw dict an app passed to send.

encode_http_scope

encode_http_scope(scope: HttpScope) -> RawScope

Render a typed HttpScope as the raw http scope dict an ASGI app expects.

The server-direction dual of parse_http_scope: a transport that owns the wire (without-http) builds the typed scope from the request line and renders it back to the dict the ASGI contract hands an app.

encode_scope

encode_scope(scope: Scope) -> RawScope

Render any typed scope as its raw ASGI dict, the dual of parse_scope.

encode_websocket_scope

encode_websocket_scope(scope: WebsocketScope) -> RawScope

Render a typed WebsocketScope as the raw websocket scope dict an ASGI app expects.

extension

extension(
    extensions: Mapping[str, Mapping[str, object]] | None,
    name: str,
) -> Mapping[str, object] | None

The named extension's advertised options, or None when it is absent.

Parse, don't validate: this returns the options mapping itself (often empty, as for http.response.trailers) rather than a bool, so a caller needing the options has them and one needing only presence checks is not None. Server-advertised extensions are optional per-connection capabilities; an app negotiates by looking one up before using it and falling back when it is None (and parse_tls reads the tls extension through this).

parse_http_scope

parse_http_scope(scope: RawScope) -> HttpScope

Read an http scope into the typed connection facts, validating at the boundary.

parse_scope

parse_scope(scope: RawScope) -> Scope

Classify any scope by its type discriminator. An unknown type is a protocol fault, so it raises.

parse_tls

parse_tls(
    extensions: Mapping[str, Mapping[str, object]] | None,
) -> Tls | None

Read the tls extension's connection info from a scope's extensions.

Returns None when the connection is not over TLS (the extension is absent), which is how an application distinguishes TLS from plaintext connections.

parse_websocket_scope

parse_websocket_scope(scope: RawScope) -> WebsocketScope

Read a websocket scope into the typed handshake facts, validating at the boundary.

http_inbound async

http_inbound(receive: Receive) -> AsyncIterator[Inbound]

An http request's inbound events as a stream.

The stream ends when the request is fully received (the last body chunk, or a disconnect), so a downstream processor's input runs dry exactly when the request does: the request's lifecycle is this stream's lifecycle.

http_outbound

http_outbound(send: Send) -> Sink[Outbound]

A sink that writes each outbound event to ASGI send, encoding at the boundary.

lifespan_inbound async

lifespan_inbound(
    receive: Receive,
) -> AsyncIterator[LifespanEvent]

The lifespan protocol's events as a stream, ending after shutdown.

lifespan_outbound

lifespan_outbound(send: Send) -> Sink[LifespanReply]

A sink that writes each lifespan reply to ASGI send, encoding at the boundary.

read_body async

read_body(events: Stream[Inbound]) -> bytes

Accumulate an http request's body across its RequestBody chunks.

Raises ClientDisconnect if the client goes away before the final chunk, so a truncated body fails loudly rather than passing for a complete one.

websocket_inbound async

websocket_inbound(
    receive: Receive,
) -> AsyncIterator[WebsocketInbound]

A websocket connection's inbound events as a stream.

The stream ends on WebsocketDisconnect, so the connection's lifecycle is this stream's lifecycle, the same shape as http_inbound.

websocket_outbound

websocket_outbound(send: Send) -> Sink[WebsocketOutbound]

A sink that writes each outbound websocket event to ASGI send, encoding at the boundary.