WSGI request scope¶
The framework-free middleware the Flask integration specialises. See the request and response integrations for which module to install.
RequestScope ¶
WSGI middleware that opens one depin scope around every request.
Implemented directly against the WSGI protocol rather than a framework's
own middleware base class, so it wraps the whole application — the
framework's own error handling and teardown callbacks included. Every WSGI
integration depin ships specialises this class, supplying only the seed
that places its own framework's request object into the frame.
The container is published to the request's context for the duration of
the scope, so depin.hosted_container() reaches it from anywhere inside
the request. The publication is undone once the scope's teardowns have
drained — including when the application returns by raising.
That scope ends when the application returns, not when the response is
finished. WSGI hands the server an iterable that the server consumes after
the application has returned, and it offers no hook that outlives that
return, so a streaming body cannot resolve: by the time the server pulls
the first chunk the scope has drained and the container is no longer
published. Resolve everything a streaming response needs before returning
the iterable, and close over the values. The alternative — materialising
the body into a list before returning it — would buy streaming safety by
buffering every response in memory, which is a worse default than the
boundary being stated, and it would defeat the one thing WSGI streaming is
for. ASGI has no such limit; depin.ext.asgi.RequestScope keeps the scope
open for the whole response.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
app
|
WSGIApp[EnvironT, StartResponseT]
|
The downstream WSGI application this middleware wraps. |
required |
container
|
FrozenContainer
|
The frozen container to host for the duration of each
request. Keyword-or-positional because the framework helpers that
install middleware pass |
required |
seed
|
ScopeSeeder[EnvironT] | None
|
Called once per request, before the downstream application runs,
to produce the key and value to place into the fresh scope frame.
Returning |
None
|
Raises:
| Type | Description |
|---|---|
TeardownError
|
An async provider left a teardown in the request's synchronous scope. A WSGI application cannot await, so an async provider has no place in one. |
ExceptionGroup
|
One or more teardowns failed when the request's scope closed. Every failure is included; one does not hide another. |
Example
Install the middleware once, per the wrapping framework's own idiom::
from depin import ScopeSeed
app.wsgi_app = RequestScope(app.wsgi_app, di, seed=lambda environ: ScopeSeed(Request, Request(environ)))
WSGIApp ¶
Bases: Protocol
Any WSGI application or middleware: the downstream peer RequestScope wraps.
Environ ¶
Environ = MutableMapping[str, object]
The per-request environment: CGI variables plus the wsgi.* server keys.
Mutable, unlike depin.ext.asgi.ASGIScope. That alias is read-only because a
framework may spell its connection scope as a TypedDict, which is not a
collections.abc.MutableMapping; WSGI has no such case — the specification
calls the environment a dictionary, and wsgiref.types.WSGIEnvironment is
dict[str, Any] — and middlewares are expected to write into it.
StartResponse ¶
Bases: Protocol
The callable a WSGI application invokes to begin the response.