tigr-asgi-contract 0.1.2.dev7__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,22 @@
1
+ from .version import CONTRACT_VERSION, CONTRACT_SERDE_VERSION
2
+ from .scope_types import ScopeType
3
+ from .bindings import Binding
4
+ from .exchanges import Exchange
5
+ from .families import Family
6
+ from .subevents import Subevent
7
+ from .completion import EmitCompletionLevel
8
+ from .capabilities import FamilyCapabilities
9
+ from .compatibility import Compatibility
10
+ from .ids import UnitIds
11
+ from .models import TlsMetadata, TransportMetadata, WebSocketScopeExt, SseScopeExt, WebTransportScopeExt, ScopeExt, DerivedEvent
12
+ from .scope import ContractScope
13
+ from .events import TransportEventType, ContractEvent
14
+ from .validators import binding_supports_family, family_supports_subevent, binding_supports_subevent, binding_family_legality, binding_subevent_legality
15
+
16
+ __all__ = [
17
+ "CONTRACT_VERSION", "CONTRACT_SERDE_VERSION", "ScopeType", "Binding", "Exchange", "Family", "Subevent",
18
+ "EmitCompletionLevel", "FamilyCapabilities", "Compatibility", "UnitIds", "TlsMetadata", "TransportMetadata",
19
+ "WebSocketScopeExt", "SseScopeExt", "WebTransportScopeExt", "ScopeExt", "DerivedEvent", "ContractScope",
20
+ "TransportEventType", "ContractEvent", "binding_supports_family", "family_supports_subevent",
21
+ "binding_supports_subevent", "binding_family_legality", "binding_subevent_legality",
22
+ ]
@@ -0,0 +1,8 @@
1
+ from __future__ import annotations
2
+ from enum import Enum
3
+
4
+ try:
5
+ from enum import StrEnum
6
+ except ImportError:
7
+ class StrEnum(str, Enum):
8
+ pass
@@ -0,0 +1,10 @@
1
+ from ._enum_compat import StrEnum
2
+
3
+
4
+ class Binding(StrEnum):
5
+ REST = 'rest'
6
+ JSONRPC = 'jsonrpc'
7
+ HTTP_STREAM = 'http.stream'
8
+ SSE = 'sse'
9
+ WEBSOCKET = 'websocket'
10
+ WEBTRANSPORT = 'webtransport'
@@ -0,0 +1,10 @@
1
+ from pydantic import BaseModel
2
+
3
+
4
+ class FamilyCapabilities(BaseModel):
5
+ request: bool = False
6
+ session: bool = False
7
+ message: bool = False
8
+ stream_in: bool = False
9
+ stream_out: bool = False
10
+ datagram: bool = False
@@ -0,0 +1,10 @@
1
+ from pydantic import BaseModel
2
+
3
+
4
+ class Compatibility(BaseModel):
5
+ contract_name: str
6
+ contract_version: str
7
+ serde_version: int
8
+ schema_draft: str
9
+ min_tigrcorn_version: str | None = None
10
+ min_tigrbl_version: str | None = None
@@ -0,0 +1,6 @@
1
+ from ._enum_compat import StrEnum
2
+
3
+
4
+ class EmitCompletionLevel(StrEnum):
5
+ ACCEPTED_BY_RUNTIME = 'accepted_by_runtime'
6
+ FLUSHED_TO_TRANSPORT = 'flushed_to_transport'
@@ -0,0 +1,29 @@
1
+ from ._enum_compat import StrEnum
2
+ from pydantic import BaseModel, Field
3
+
4
+
5
+ class TransportEventType(StrEnum):
6
+ HTTP_REQUEST = 'http.request'
7
+ HTTP_DISCONNECT = 'http.disconnect'
8
+ HTTP_RESPONSE_START = 'http.response.start'
9
+ HTTP_RESPONSE_BODY = 'http.response.body'
10
+ WEBSOCKET_CONNECT = 'websocket.connect'
11
+ WEBSOCKET_RECEIVE = 'websocket.receive'
12
+ WEBSOCKET_DISCONNECT = 'websocket.disconnect'
13
+ WEBSOCKET_ACCEPT = 'websocket.accept'
14
+ WEBSOCKET_SEND = 'websocket.send'
15
+ WEBSOCKET_CLOSE = 'websocket.close'
16
+ WEBTRANSPORT_CONNECT = 'webtransport.connect'
17
+ WEBTRANSPORT_ACCEPT = 'webtransport.accept'
18
+ WEBTRANSPORT_STREAM_RECEIVE = 'webtransport.stream.receive'
19
+ WEBTRANSPORT_STREAM_SEND = 'webtransport.stream.send'
20
+ WEBTRANSPORT_DATAGRAM_RECEIVE = 'webtransport.datagram.receive'
21
+ WEBTRANSPORT_DATAGRAM_SEND = 'webtransport.datagram.send'
22
+ WEBTRANSPORT_DISCONNECT = 'webtransport.disconnect'
23
+ WEBTRANSPORT_CLOSE = 'webtransport.close'
24
+ TRANSPORT_EMIT_COMPLETE = 'transport.emit.complete'
25
+
26
+
27
+ class ContractEvent(BaseModel):
28
+ type: TransportEventType
29
+ payload: dict = Field(default_factory=dict)
@@ -0,0 +1,7 @@
1
+ from ._enum_compat import StrEnum
2
+
3
+
4
+ class Exchange(StrEnum):
5
+ UNARY = 'unary'
6
+ SERVER_STREAM = 'server_stream'
7
+ DUPLEX = 'duplex'
@@ -0,0 +1,9 @@
1
+ from ._enum_compat import StrEnum
2
+
3
+
4
+ class Family(StrEnum):
5
+ REQUEST = 'request'
6
+ SESSION = 'session'
7
+ MESSAGE = 'message'
8
+ STREAM = 'stream'
9
+ DATAGRAM = 'datagram'
@@ -0,0 +1,10 @@
1
+ from pydantic import BaseModel
2
+
3
+
4
+ class UnitIds(BaseModel):
5
+ unit_id: str | None = None
6
+ parent_unit_id: str | None = None
7
+ session_id: str | None = None
8
+ stream_id: int | None = None
9
+ datagram_id: int | None = None
10
+ emit_id: str | None = None
@@ -0,0 +1,50 @@
1
+ from pydantic import BaseModel
2
+ from .capabilities import FamilyCapabilities
3
+
4
+
5
+ class TlsMetadata(BaseModel):
6
+ version: str | None = None
7
+ cipher: str | None = None
8
+ verified: bool = False
9
+ peer_identity: str | None = None
10
+ peer_cert: dict | None = None
11
+
12
+
13
+ class TransportMetadata(BaseModel):
14
+ binding: str
15
+ network: str
16
+ secure: bool
17
+ alpn: str | None = None
18
+ tls: TlsMetadata | None = None
19
+ framing: str | None = None
20
+
21
+
22
+ class WebSocketScopeExt(BaseModel):
23
+ subprotocol: str | None = None
24
+
25
+
26
+ class SseScopeExt(BaseModel):
27
+ retry_ms: int | None = None
28
+ last_event_id: str | None = None
29
+
30
+
31
+ class WebTransportScopeExt(BaseModel):
32
+ session_id: str | None = None
33
+ supports_datagrams: bool = False
34
+ supports_bidi_streams: bool = False
35
+ supports_uni_streams: bool = False
36
+ max_datagram_size: int | None = None
37
+
38
+
39
+ class ScopeExt(BaseModel):
40
+ transport: TransportMetadata
41
+ family_capabilities: FamilyCapabilities
42
+ websocket: WebSocketScopeExt | None = None
43
+ sse: SseScopeExt | None = None
44
+ webtransport: WebTransportScopeExt | None = None
45
+
46
+
47
+ class DerivedEvent(BaseModel):
48
+ family: str
49
+ subevent: str
50
+ repeated: bool = False
@@ -0,0 +1,366 @@
1
+ BINDING_FAMILY_MATRIX = {
2
+ "rest": {
3
+ "request": "R",
4
+ "session": "F",
5
+ "message": "F",
6
+ "stream": "O",
7
+ "datagram": "F"
8
+ },
9
+ "jsonrpc": {
10
+ "request": "R",
11
+ "session": "F",
12
+ "message": "F",
13
+ "stream": "O",
14
+ "datagram": "F"
15
+ },
16
+ "http.stream": {
17
+ "request": "R",
18
+ "session": "F",
19
+ "message": "F",
20
+ "stream": "R",
21
+ "datagram": "F"
22
+ },
23
+ "sse": {
24
+ "request": "R",
25
+ "session": "R",
26
+ "message": "R",
27
+ "stream": "R",
28
+ "datagram": "F"
29
+ },
30
+ "websocket": {
31
+ "request": "F",
32
+ "session": "R",
33
+ "message": "R",
34
+ "stream": "F",
35
+ "datagram": "F"
36
+ },
37
+ "webtransport": {
38
+ "request": "F",
39
+ "session": "R",
40
+ "message": "O",
41
+ "stream": "R",
42
+ "datagram": "R"
43
+ }
44
+ }
45
+
46
+ FAMILY_SUBEVENT_MATRIX = {
47
+ "request": {
48
+ "request.open": "R",
49
+ "request.body_in": "R",
50
+ "request.chunk_in": "R",
51
+ "request.accept": "R",
52
+ "request.close": "R",
53
+ "request.disconnect": "R",
54
+ "response.open": "R",
55
+ "response.body_out": "R",
56
+ "response.chunk_out": "R",
57
+ "response.close": "R",
58
+ "response.emit_complete": "R"
59
+ },
60
+ "session": {
61
+ "session.open": "R",
62
+ "session.accept": "R",
63
+ "session.ready": "R",
64
+ "session.heartbeat": "R",
65
+ "session.sync": "R",
66
+ "session.close": "R",
67
+ "session.disconnect": "R",
68
+ "session.emit_complete": "R"
69
+ },
70
+ "message": {
71
+ "message.in": "R",
72
+ "message.decode": "R",
73
+ "message.handle": "R",
74
+ "message.out": "R",
75
+ "message.ack": "R",
76
+ "message.nack": "R",
77
+ "message.replay": "R",
78
+ "message.snapshot": "R",
79
+ "message.emit_complete": "R"
80
+ },
81
+ "stream": {
82
+ "stream.open": "R",
83
+ "stream.chunk_in": "R",
84
+ "stream.chunk_out": "R",
85
+ "stream.flush": "R",
86
+ "stream.finalize": "R",
87
+ "stream.abort": "R",
88
+ "stream.close": "R",
89
+ "stream.emit_complete": "R"
90
+ },
91
+ "datagram": {
92
+ "datagram.in": "R",
93
+ "datagram.handle": "R",
94
+ "datagram.out": "R",
95
+ "datagram.ack": "R",
96
+ "datagram.close": "R",
97
+ "datagram.emit_complete": "R"
98
+ }
99
+ }
100
+
101
+ BINDING_SUBEVENT_MATRIX = {
102
+ "rest": {
103
+ "request.open": "R",
104
+ "request.body_in": "R",
105
+ "request.chunk_in": "F",
106
+ "request.accept": "O",
107
+ "request.close": "R",
108
+ "request.disconnect": "O",
109
+ "response.open": "R",
110
+ "response.body_out": "R",
111
+ "response.chunk_out": "F",
112
+ "response.close": "O",
113
+ "response.emit_complete": "R",
114
+ "session.open": "F",
115
+ "session.accept": "F",
116
+ "session.ready": "F",
117
+ "session.heartbeat": "F",
118
+ "session.sync": "F",
119
+ "session.close": "F",
120
+ "session.disconnect": "F",
121
+ "session.emit_complete": "F",
122
+ "message.in": "F",
123
+ "message.decode": "F",
124
+ "message.handle": "F",
125
+ "message.out": "F",
126
+ "message.ack": "F",
127
+ "message.nack": "F",
128
+ "message.replay": "F",
129
+ "message.snapshot": "F",
130
+ "message.emit_complete": "F",
131
+ "stream.open": "O",
132
+ "stream.chunk_in": "O",
133
+ "stream.chunk_out": "O",
134
+ "stream.flush": "F",
135
+ "stream.finalize": "O",
136
+ "stream.abort": "F",
137
+ "stream.close": "O",
138
+ "stream.emit_complete": "O",
139
+ "datagram.in": "F",
140
+ "datagram.handle": "F",
141
+ "datagram.out": "F",
142
+ "datagram.ack": "F",
143
+ "datagram.close": "F",
144
+ "datagram.emit_complete": "F"
145
+ },
146
+ "jsonrpc": {
147
+ "request.open": "R",
148
+ "request.body_in": "R",
149
+ "request.chunk_in": "F",
150
+ "request.accept": "O",
151
+ "request.close": "R",
152
+ "request.disconnect": "O",
153
+ "response.open": "R",
154
+ "response.body_out": "R",
155
+ "response.chunk_out": "F",
156
+ "response.close": "O",
157
+ "response.emit_complete": "R",
158
+ "session.open": "F",
159
+ "session.accept": "F",
160
+ "session.ready": "F",
161
+ "session.heartbeat": "F",
162
+ "session.sync": "F",
163
+ "session.close": "F",
164
+ "session.disconnect": "F",
165
+ "session.emit_complete": "F",
166
+ "message.in": "F",
167
+ "message.decode": "D",
168
+ "message.handle": "F",
169
+ "message.out": "F",
170
+ "message.ack": "F",
171
+ "message.nack": "F",
172
+ "message.replay": "F",
173
+ "message.snapshot": "F",
174
+ "message.emit_complete": "F",
175
+ "stream.open": "O",
176
+ "stream.chunk_in": "O",
177
+ "stream.chunk_out": "O",
178
+ "stream.flush": "F",
179
+ "stream.finalize": "O",
180
+ "stream.abort": "F",
181
+ "stream.close": "O",
182
+ "stream.emit_complete": "O",
183
+ "datagram.in": "F",
184
+ "datagram.handle": "F",
185
+ "datagram.out": "F",
186
+ "datagram.ack": "F",
187
+ "datagram.close": "F",
188
+ "datagram.emit_complete": "F"
189
+ },
190
+ "http.stream": {
191
+ "request.open": "R",
192
+ "request.body_in": "O",
193
+ "request.chunk_in": "D",
194
+ "request.accept": "O",
195
+ "request.close": "R",
196
+ "request.disconnect": "O",
197
+ "response.open": "R",
198
+ "response.body_out": "O",
199
+ "response.chunk_out": "D",
200
+ "response.close": "O",
201
+ "response.emit_complete": "R",
202
+ "session.open": "F",
203
+ "session.accept": "F",
204
+ "session.ready": "F",
205
+ "session.heartbeat": "F",
206
+ "session.sync": "F",
207
+ "session.close": "F",
208
+ "session.disconnect": "F",
209
+ "session.emit_complete": "F",
210
+ "message.in": "F",
211
+ "message.decode": "F",
212
+ "message.handle": "F",
213
+ "message.out": "F",
214
+ "message.ack": "F",
215
+ "message.nack": "F",
216
+ "message.replay": "F",
217
+ "message.snapshot": "F",
218
+ "message.emit_complete": "F",
219
+ "stream.open": "R",
220
+ "stream.chunk_in": "R",
221
+ "stream.chunk_out": "R",
222
+ "stream.flush": "O",
223
+ "stream.finalize": "R",
224
+ "stream.abort": "O",
225
+ "stream.close": "R",
226
+ "stream.emit_complete": "R",
227
+ "datagram.in": "F",
228
+ "datagram.handle": "F",
229
+ "datagram.out": "F",
230
+ "datagram.ack": "F",
231
+ "datagram.close": "F",
232
+ "datagram.emit_complete": "F"
233
+ },
234
+ "sse": {
235
+ "request.open": "R",
236
+ "request.body_in": "O",
237
+ "request.chunk_in": "F",
238
+ "request.accept": "O",
239
+ "request.close": "R",
240
+ "request.disconnect": "O",
241
+ "response.open": "O",
242
+ "response.body_out": "F",
243
+ "response.chunk_out": "D",
244
+ "response.close": "O",
245
+ "response.emit_complete": "R",
246
+ "session.open": "R",
247
+ "session.accept": "R",
248
+ "session.ready": "R",
249
+ "session.heartbeat": "O",
250
+ "session.sync": "O",
251
+ "session.close": "R",
252
+ "session.disconnect": "O",
253
+ "session.emit_complete": "O",
254
+ "message.in": "F",
255
+ "message.decode": "F",
256
+ "message.handle": "F",
257
+ "message.out": "R",
258
+ "message.ack": "F",
259
+ "message.nack": "F",
260
+ "message.replay": "O",
261
+ "message.snapshot": "O",
262
+ "message.emit_complete": "R",
263
+ "stream.open": "R",
264
+ "stream.chunk_in": "F",
265
+ "stream.chunk_out": "R",
266
+ "stream.flush": "O",
267
+ "stream.finalize": "O",
268
+ "stream.abort": "O",
269
+ "stream.close": "R",
270
+ "stream.emit_complete": "R",
271
+ "datagram.in": "F",
272
+ "datagram.handle": "F",
273
+ "datagram.out": "F",
274
+ "datagram.ack": "F",
275
+ "datagram.close": "F",
276
+ "datagram.emit_complete": "F"
277
+ },
278
+ "websocket": {
279
+ "request.open": "F",
280
+ "request.body_in": "F",
281
+ "request.chunk_in": "F",
282
+ "request.accept": "F",
283
+ "request.close": "F",
284
+ "request.disconnect": "F",
285
+ "response.open": "F",
286
+ "response.body_out": "F",
287
+ "response.chunk_out": "F",
288
+ "response.close": "F",
289
+ "response.emit_complete": "F",
290
+ "session.open": "R",
291
+ "session.accept": "R",
292
+ "session.ready": "R",
293
+ "session.heartbeat": "O",
294
+ "session.sync": "O",
295
+ "session.close": "R",
296
+ "session.disconnect": "O",
297
+ "session.emit_complete": "O",
298
+ "message.in": "R",
299
+ "message.decode": "O",
300
+ "message.handle": "R",
301
+ "message.out": "R",
302
+ "message.ack": "O",
303
+ "message.nack": "O",
304
+ "message.replay": "O",
305
+ "message.snapshot": "O",
306
+ "message.emit_complete": "R",
307
+ "stream.open": "F",
308
+ "stream.chunk_in": "F",
309
+ "stream.chunk_out": "F",
310
+ "stream.flush": "F",
311
+ "stream.finalize": "F",
312
+ "stream.abort": "F",
313
+ "stream.close": "F",
314
+ "stream.emit_complete": "F",
315
+ "datagram.in": "F",
316
+ "datagram.handle": "F",
317
+ "datagram.out": "F",
318
+ "datagram.ack": "F",
319
+ "datagram.close": "F",
320
+ "datagram.emit_complete": "F"
321
+ },
322
+ "webtransport": {
323
+ "request.open": "F",
324
+ "request.body_in": "F",
325
+ "request.chunk_in": "F",
326
+ "request.accept": "F",
327
+ "request.close": "F",
328
+ "request.disconnect": "F",
329
+ "response.open": "F",
330
+ "response.body_out": "F",
331
+ "response.chunk_out": "F",
332
+ "response.close": "F",
333
+ "response.emit_complete": "F",
334
+ "session.open": "R",
335
+ "session.accept": "R",
336
+ "session.ready": "R",
337
+ "session.heartbeat": "O",
338
+ "session.sync": "O",
339
+ "session.close": "R",
340
+ "session.disconnect": "O",
341
+ "session.emit_complete": "O",
342
+ "message.in": "O",
343
+ "message.decode": "O",
344
+ "message.handle": "O",
345
+ "message.out": "O",
346
+ "message.ack": "O",
347
+ "message.nack": "O",
348
+ "message.replay": "O",
349
+ "message.snapshot": "O",
350
+ "message.emit_complete": "O",
351
+ "stream.open": "R",
352
+ "stream.chunk_in": "R",
353
+ "stream.chunk_out": "R",
354
+ "stream.flush": "O",
355
+ "stream.finalize": "R",
356
+ "stream.abort": "O",
357
+ "stream.close": "R",
358
+ "stream.emit_complete": "R",
359
+ "datagram.in": "R",
360
+ "datagram.handle": "R",
361
+ "datagram.out": "R",
362
+ "datagram.ack": "O",
363
+ "datagram.close": "R",
364
+ "datagram.emit_complete": "R"
365
+ }
366
+ }
@@ -0,0 +1,16 @@
1
+ from pydantic import BaseModel
2
+ from .models import ScopeExt
3
+
4
+
5
+ class ContractScope(BaseModel):
6
+ type: str
7
+ asgi: dict
8
+ scheme: str
9
+ http_version: str | None = None
10
+ method: str | None = None
11
+ path: str
12
+ query_string: bytes = b""
13
+ headers: list[tuple[bytes, bytes]]
14
+ client: tuple[str, int] | None = None
15
+ server: tuple[str, int] | None = None
16
+ ext: ScopeExt
@@ -0,0 +1,8 @@
1
+ from ._enum_compat import StrEnum
2
+
3
+
4
+ class ScopeType(StrEnum):
5
+ HTTP = 'http'
6
+ WEBSOCKET = 'websocket'
7
+ LIFESPAN = 'lifespan'
8
+ WEBTRANSPORT = 'webtransport'
@@ -0,0 +1,46 @@
1
+ from ._enum_compat import StrEnum
2
+
3
+
4
+ class Subevent(StrEnum):
5
+ REQUEST_OPEN = 'request.open'
6
+ REQUEST_BODY_IN = 'request.body_in'
7
+ REQUEST_CHUNK_IN = 'request.chunk_in'
8
+ REQUEST_ACCEPT = 'request.accept'
9
+ REQUEST_CLOSE = 'request.close'
10
+ REQUEST_DISCONNECT = 'request.disconnect'
11
+ RESPONSE_OPEN = 'response.open'
12
+ RESPONSE_BODY_OUT = 'response.body_out'
13
+ RESPONSE_CHUNK_OUT = 'response.chunk_out'
14
+ RESPONSE_CLOSE = 'response.close'
15
+ RESPONSE_EMIT_COMPLETE = 'response.emit_complete'
16
+ SESSION_OPEN = 'session.open'
17
+ SESSION_ACCEPT = 'session.accept'
18
+ SESSION_READY = 'session.ready'
19
+ SESSION_HEARTBEAT = 'session.heartbeat'
20
+ SESSION_SYNC = 'session.sync'
21
+ SESSION_CLOSE = 'session.close'
22
+ SESSION_DISCONNECT = 'session.disconnect'
23
+ SESSION_EMIT_COMPLETE = 'session.emit_complete'
24
+ MESSAGE_IN = 'message.in'
25
+ MESSAGE_DECODE = 'message.decode'
26
+ MESSAGE_HANDLE = 'message.handle'
27
+ MESSAGE_OUT = 'message.out'
28
+ MESSAGE_ACK = 'message.ack'
29
+ MESSAGE_NACK = 'message.nack'
30
+ MESSAGE_REPLAY = 'message.replay'
31
+ MESSAGE_SNAPSHOT = 'message.snapshot'
32
+ MESSAGE_EMIT_COMPLETE = 'message.emit_complete'
33
+ STREAM_OPEN = 'stream.open'
34
+ STREAM_CHUNK_IN = 'stream.chunk_in'
35
+ STREAM_CHUNK_OUT = 'stream.chunk_out'
36
+ STREAM_FLUSH = 'stream.flush'
37
+ STREAM_FINALIZE = 'stream.finalize'
38
+ STREAM_ABORT = 'stream.abort'
39
+ STREAM_CLOSE = 'stream.close'
40
+ STREAM_EMIT_COMPLETE = 'stream.emit_complete'
41
+ DATAGRAM_IN = 'datagram.in'
42
+ DATAGRAM_HANDLE = 'datagram.handle'
43
+ DATAGRAM_OUT = 'datagram.out'
44
+ DATAGRAM_ACK = 'datagram.ack'
45
+ DATAGRAM_CLOSE = 'datagram.close'
46
+ DATAGRAM_EMIT_COMPLETE = 'datagram.emit_complete'
@@ -0,0 +1,22 @@
1
+ from __future__ import annotations
2
+ from .registry import BINDING_FAMILY_MATRIX, FAMILY_SUBEVENT_MATRIX, BINDING_SUBEVENT_MATRIX
3
+
4
+
5
+ def binding_supports_family(binding: str, family: str) -> bool:
6
+ return BINDING_FAMILY_MATRIX[binding][family] != "F"
7
+
8
+
9
+ def family_supports_subevent(family: str, subevent: str) -> bool:
10
+ return FAMILY_SUBEVENT_MATRIX[family].get(subevent) != "F"
11
+
12
+
13
+ def binding_supports_subevent(binding: str, subevent: str) -> bool:
14
+ return BINDING_SUBEVENT_MATRIX[binding].get(subevent) != "F"
15
+
16
+
17
+ def binding_family_legality(binding: str, family: str) -> str:
18
+ return BINDING_FAMILY_MATRIX[binding][family]
19
+
20
+
21
+ def binding_subevent_legality(binding: str, subevent: str) -> str:
22
+ return BINDING_SUBEVENT_MATRIX[binding][subevent]
@@ -0,0 +1,2 @@
1
+ CONTRACT_VERSION = "0.1.2-dev7"
2
+ CONTRACT_SERDE_VERSION = 1