Incorrect typing for Scope and Message in ASGIApp
ods opened this issue · comments
Denis Otkidach commented
- Initially raised as discussion #2040 (but ignored there)
According to ASGI spec both scope and event message must be dictionaries, not an arbitrary mutable mapping:
scope
: The connection scope information, a dictionary that contains at least atype
key specifying the protocol that is incomingreceive
: an awaitable callable that will yield a new event dictionary when one is availablesend
: an awaitable callable taking a single event dictionary as a positional argument that will return once the send has been completed or the connection has been closed
and in other place:
scope
must be adict
.
But in starlette they are declared as MutableMapping
:
Scope = typing.MutableMapping[str, typing.Any]
Message = typing.MutableMapping[str, typing.Any]
Receive = typing.Callable[[], typing.Awaitable[Message]]
Send = typing.Callable[[Message], typing.Awaitable[None]]
ASGIApp = typing.Callable[[Scope, Receive, Send], typing.Awaitable[None]]
This actually breaks interoperability with other libraries that follows the spec. For example, the following code
from starlette.applications import Starlette
from httpx import ASGITransport
ASGITransport(Starlette())
gives the following error when type-checked with mypy:
error: Argument 1 to "ASGITransport" has incompatible type "Starlette"; expected "Callable[[Dict[str, Any], Callable[[], Awaitable[Dict[str, Any]]], Callable[[Dict[str, Any]], Coroutine[None, None, None]]], Coroutine[None, None, None]]" [arg-type]
note: "Starlette.__call__" has type "Callable[[Arg(MutableMapping[str, Any], 'scope'), Arg(Callable[[], Awaitable[MutableMapping[str, Any]]], 'receive'), Arg(Callable[[MutableMapping[str, Any]], Awaitable[None]], 'send')], Coroutine[Any, Any, None]]"
The typing of ASGI app in httpx follows the spec:
_Message = typing.Dict[str, typing.Any]
_Receive = typing.Callable[[], typing.Awaitable[_Message]]
_Send = typing.Callable[
[typing.Dict[str, typing.Any]], typing.Coroutine[None, None, None]
]
_ASGIApp = typing.Callable[
[typing.Dict[str, typing.Any], _Receive, _Send], typing.Coroutine[None, None, None]
]