Skip to content

Commit cf99cb7

Browse files
authoredJan 17, 2021
Added typing for ASGI Scopes, messages, and frameworks
These are useful for users of asgiref to type check their ASGI usage. It also serves as the reference typing for the ASGI Specification. This does not include typing for the actual ASGI functions (yet).
1 parent 6ac90bc commit cf99cb7

File tree

2 files changed

+209
-0
lines changed

2 files changed

+209
-0
lines changed
 

‎asgiref/typing.py

+204
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,204 @@
1+
from typing import Awaitable, Callable, Dict, Iterable, Optional, Tuple, Type, Union
2+
3+
try:
4+
from typing import Literal, Protocol, TypedDict
5+
except ImportError:
6+
from typing_extensions import Literal, Protocol, TypedDict # type: ignore
7+
8+
9+
class ASGIVersions(TypedDict):
10+
spec_version: str
11+
version: Union[Literal["2.0"], Literal["3.0"]]
12+
13+
14+
class HTTPScope(TypedDict):
15+
type: Literal["http"]
16+
asgi: ASGIVersions
17+
http_version: str
18+
method: str
19+
scheme: str
20+
path: str
21+
raw_path: bytes
22+
query_string: bytes
23+
root_path: str
24+
headers: Iterable[Tuple[bytes, bytes]]
25+
client: Optional[Tuple[str, int]]
26+
server: Optional[Tuple[str, Optional[int]]]
27+
extensions: Dict[str, dict]
28+
29+
30+
class WebsocketScope(TypedDict):
31+
type: Literal["websocket"]
32+
asgi: ASGIVersions
33+
http_version: str
34+
scheme: str
35+
path: str
36+
raw_path: bytes
37+
query_string: bytes
38+
root_path: str
39+
headers: Iterable[Tuple[bytes, bytes]]
40+
client: Optional[Tuple[str, int]]
41+
server: Optional[Tuple[str, Optional[int]]]
42+
subprotocols: Iterable[str]
43+
extensions: Dict[str, dict]
44+
45+
46+
class LifespanScope(TypedDict):
47+
type: Literal["lifespan"]
48+
asgi: ASGIVersions
49+
50+
51+
WWWScope = Union[HTTPScope, WebsocketScope]
52+
Scope = Union[HTTPScope, WebsocketScope, LifespanScope]
53+
54+
55+
class HTTPRequestEvent(TypedDict):
56+
type: Literal["http.request"]
57+
body: bytes
58+
more_body: bool
59+
60+
61+
class HTTPResponseStartEvent(TypedDict):
62+
type: Literal["http.response.start"]
63+
status: int
64+
headers: Iterable[Tuple[bytes, bytes]]
65+
66+
67+
class HTTPResponseBodyEvent(TypedDict):
68+
type: Literal["http.response.body"]
69+
body: bytes
70+
more_body: bool
71+
72+
73+
class HTTPServerPushEvent(TypedDict):
74+
type: Literal["http.response.push"]
75+
path: str
76+
headers: Iterable[Tuple[bytes, bytes]]
77+
78+
79+
class HTTPDisconnectEvent(TypedDict):
80+
type: Literal["http.disconnect"]
81+
82+
83+
class WebsocketConnectEvent(TypedDict):
84+
type: Literal["websocket.connect"]
85+
86+
87+
class WebsocketAcceptEvent(TypedDict):
88+
type: Literal["websocket.accept"]
89+
subprotocol: Optional[str]
90+
headers: Iterable[Tuple[bytes, bytes]]
91+
92+
93+
class WebsocketReceiveEvent(TypedDict):
94+
type: Literal["websocket.receive"]
95+
bytes: Optional[bytes]
96+
text: Optional[str]
97+
98+
99+
class WebsocketSendEvent(TypedDict):
100+
type: Literal["websocket.send"]
101+
bytes: Optional[bytes]
102+
text: Optional[str]
103+
104+
105+
class WebsocketResponseStartEvent(TypedDict):
106+
type: Literal["websocket.http.response.start"]
107+
status: int
108+
headers: Iterable[Tuple[bytes, bytes]]
109+
110+
111+
class WebsocketResponseBodyEvent(TypedDict):
112+
type: Literal["websocket.http.response.body"]
113+
body: bytes
114+
more_body: bool
115+
116+
117+
class WebsocketDisconnectEvent(TypedDict):
118+
type: Literal["websocket.disconnect"]
119+
code: int
120+
121+
122+
class WebsocketCloseEvent(TypedDict):
123+
type: Literal["websocket.close"]
124+
code: int
125+
126+
127+
class LifespanStartupEvent(TypedDict):
128+
type: Literal["lifespan.startup"]
129+
130+
131+
class LifespanShutdownEvent(TypedDict):
132+
type: Literal["lifespan.shutdown"]
133+
134+
135+
class LifespanStartupCompleteEvent(TypedDict):
136+
type: Literal["lifespan.startup.complete"]
137+
138+
139+
class LifespanStartupFailedEvent(TypedDict):
140+
type: Literal["lifespan.startup.failed"]
141+
message: str
142+
143+
144+
class LifespanShutdownCompleteEvent(TypedDict):
145+
type: Literal["lifespan.shutdown.complete"]
146+
147+
148+
class LifespanShutdownFailedEvent(TypedDict):
149+
type: Literal["lifespan.shutdown.failed"]
150+
message: str
151+
152+
153+
ASGIReceiveEvent = Union[
154+
HTTPRequestEvent,
155+
HTTPDisconnectEvent,
156+
WebsocketConnectEvent,
157+
WebsocketReceiveEvent,
158+
WebsocketDisconnectEvent,
159+
LifespanStartupEvent,
160+
LifespanShutdownEvent,
161+
]
162+
163+
164+
ASGISendEvent = Union[
165+
HTTPResponseStartEvent,
166+
HTTPResponseBodyEvent,
167+
HTTPServerPushEvent,
168+
HTTPDisconnectEvent,
169+
WebsocketAcceptEvent,
170+
WebsocketSendEvent,
171+
WebsocketResponseStartEvent,
172+
WebsocketResponseBodyEvent,
173+
WebsocketCloseEvent,
174+
LifespanStartupCompleteEvent,
175+
LifespanStartupFailedEvent,
176+
LifespanShutdownCompleteEvent,
177+
LifespanShutdownFailedEvent,
178+
]
179+
180+
181+
ASGIReceiveCallable = Callable[[], Awaitable[ASGIReceiveEvent]]
182+
ASGISendCallable = Callable[[ASGISendEvent], Awaitable[None]]
183+
184+
185+
class ASGI2Protocol(Protocol):
186+
def __init__(self, scope: Scope) -> None:
187+
...
188+
189+
async def __call__(
190+
self, receive: ASGIReceiveCallable, send: ASGISendCallable
191+
) -> None:
192+
...
193+
194+
195+
ASGI2Application = Type[ASGI2Protocol]
196+
ASGI3Application = Callable[
197+
[
198+
Scope,
199+
ASGIReceiveCallable,
200+
ASGISendCallable,
201+
],
202+
Awaitable[None],
203+
]
204+
ASGIApplication = Union[ASGI2Application, ASGI3Application]

‎setup.cfg

+5
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ project_urls =
3131
python_requires = >=3.5
3232
packages = find:
3333
include_package_data = true
34+
install_requires =
35+
typing_extensions; python_version < "3.8"
3436
zip_safe = false
3537

3638
[options.extras_require]
@@ -45,3 +47,6 @@ testpaths = tests
4547
exclude = venv/*,tox/*,specs/*
4648
ignore = E123,E128,E266,E402,W503,E731,W601
4749
max-line-length = 119
50+
51+
[isort]
52+
line_length = 119

0 commit comments

Comments
 (0)
Please sign in to comment.