omextra 0.0.0.dev424__py3-none-any.whl → 0.0.0.dev426__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.
Files changed (68) hide show
  1. omextra/.omlish-manifests.json +14 -0
  2. omextra/__about__.py +3 -1
  3. omextra/defs.py +216 -0
  4. omextra/dynamic.py +219 -0
  5. omextra/formats/__init__.py +0 -0
  6. omextra/formats/json/Json.g4 +77 -0
  7. omextra/formats/json/__init__.py +0 -0
  8. omextra/formats/json/_antlr/JsonLexer.py +109 -0
  9. omextra/formats/json/_antlr/JsonListener.py +61 -0
  10. omextra/formats/json/_antlr/JsonParser.py +457 -0
  11. omextra/formats/json/_antlr/JsonVisitor.py +42 -0
  12. omextra/formats/json/_antlr/__init__.py +0 -0
  13. omextra/io/__init__.py +0 -0
  14. omextra/io/trampoline.py +289 -0
  15. omextra/specs/__init__.py +0 -0
  16. omextra/specs/irc/__init__.py +0 -0
  17. omextra/specs/irc/messages/__init__.py +0 -0
  18. omextra/specs/irc/messages/base.py +50 -0
  19. omextra/specs/irc/messages/formats.py +92 -0
  20. omextra/specs/irc/messages/messages.py +775 -0
  21. omextra/specs/irc/messages/parsing.py +99 -0
  22. omextra/specs/irc/numerics/__init__.py +0 -0
  23. omextra/specs/irc/numerics/formats.py +97 -0
  24. omextra/specs/irc/numerics/numerics.py +865 -0
  25. omextra/specs/irc/numerics/types.py +59 -0
  26. omextra/specs/irc/protocol/LICENSE +11 -0
  27. omextra/specs/irc/protocol/__init__.py +61 -0
  28. omextra/specs/irc/protocol/consts.py +6 -0
  29. omextra/specs/irc/protocol/errors.py +30 -0
  30. omextra/specs/irc/protocol/message.py +21 -0
  31. omextra/specs/irc/protocol/nuh.py +55 -0
  32. omextra/specs/irc/protocol/parsing.py +158 -0
  33. omextra/specs/irc/protocol/rendering.py +153 -0
  34. omextra/specs/irc/protocol/tags.py +102 -0
  35. omextra/specs/irc/protocol/utils.py +30 -0
  36. omextra/specs/proto/Protobuf3.g4 +396 -0
  37. omextra/specs/proto/__init__.py +0 -0
  38. omextra/specs/proto/_antlr/Protobuf3Lexer.py +340 -0
  39. omextra/specs/proto/_antlr/Protobuf3Listener.py +448 -0
  40. omextra/specs/proto/_antlr/Protobuf3Parser.py +3909 -0
  41. omextra/specs/proto/_antlr/Protobuf3Visitor.py +257 -0
  42. omextra/specs/proto/_antlr/__init__.py +0 -0
  43. omextra/specs/proto/nodes.py +54 -0
  44. omextra/specs/proto/parsing.py +98 -0
  45. omextra/sql/__init__.py +0 -0
  46. omextra/sql/parsing/Minisql.g4 +292 -0
  47. omextra/sql/parsing/__init__.py +0 -0
  48. omextra/sql/parsing/_antlr/MinisqlLexer.py +322 -0
  49. omextra/sql/parsing/_antlr/MinisqlListener.py +511 -0
  50. omextra/sql/parsing/_antlr/MinisqlParser.py +3763 -0
  51. omextra/sql/parsing/_antlr/MinisqlVisitor.py +292 -0
  52. omextra/sql/parsing/_antlr/__init__.py +0 -0
  53. omextra/sql/parsing/parsing.py +120 -0
  54. omextra/text/__init__.py +0 -0
  55. omextra/text/antlr/__init__.py +0 -0
  56. omextra/text/antlr/cli/__init__.py +0 -0
  57. omextra/text/antlr/cli/__main__.py +11 -0
  58. omextra/text/antlr/cli/cli.py +62 -0
  59. omextra/text/antlr/cli/consts.py +7 -0
  60. omextra/text/antlr/cli/gen.py +193 -0
  61. {omextra-0.0.0.dev424.dist-info → omextra-0.0.0.dev426.dist-info}/METADATA +2 -3
  62. omextra-0.0.0.dev426.dist-info/RECORD +67 -0
  63. omextra/.manifests.json +0 -1
  64. omextra-0.0.0.dev424.dist-info/RECORD +0 -9
  65. {omextra-0.0.0.dev424.dist-info → omextra-0.0.0.dev426.dist-info}/WHEEL +0 -0
  66. {omextra-0.0.0.dev424.dist-info → omextra-0.0.0.dev426.dist-info}/entry_points.txt +0 -0
  67. {omextra-0.0.0.dev424.dist-info → omextra-0.0.0.dev426.dist-info}/licenses/LICENSE +0 -0
  68. {omextra-0.0.0.dev424.dist-info → omextra-0.0.0.dev426.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,289 @@
1
+ import abc
2
+ import contextlib
3
+ import io
4
+ import typing as ta
5
+
6
+ from omlish import check
7
+ from omlish import lang
8
+ from omlish.concurrent import threadlets as tls
9
+ from omlish.sync import ConditionDeque
10
+
11
+
12
+ if ta.TYPE_CHECKING:
13
+ import threading
14
+
15
+ from omlish.io import pyio # noqa
16
+
17
+ else:
18
+ threading = lang.proxy_import('threading')
19
+
20
+ pyio = lang.proxy_import('omlish.io.pyio')
21
+
22
+
23
+ T = ta.TypeVar('T')
24
+
25
+ BytesLike: ta.TypeAlias = ta.Any
26
+
27
+ BufferedReader: ta.TypeAlias = io.BufferedReader
28
+ # BufferedReader: ta.TypeAlias = pyio.BufferedReader
29
+
30
+
31
+ ##
32
+
33
+
34
+ class ProxyReadFile:
35
+ def __init__(self, read: ta.Callable[[int], bytes | BaseException]) -> None:
36
+ super().__init__()
37
+
38
+ self._read = read
39
+ self._eof = False
40
+ self._closed = False
41
+
42
+ #
43
+
44
+ def read(self, n: int, /) -> bytes:
45
+ if self._closed:
46
+ raise RuntimeError('Closed')
47
+ if self._eof:
48
+ return b''
49
+ d = self._read(n)
50
+ if isinstance(d, BaseException):
51
+ raise d
52
+ if not d:
53
+ self._eof = True
54
+ return d
55
+
56
+ def readall(self, *args, **kwargs):
57
+ raise TypeError # FIXME
58
+
59
+ def readinto(self, b: BytesLike) -> int | None:
60
+ d = self.read(len(b))
61
+ if d:
62
+ b[:len(d)] = d
63
+ return len(d)
64
+
65
+ #
66
+
67
+ def readable(self) -> bool:
68
+ return not (self._eof or self._closed)
69
+
70
+ @property
71
+ def closed(self) -> bool:
72
+ return self._closed
73
+
74
+ def close(self) -> None:
75
+ self._closed = True
76
+
77
+ #
78
+
79
+ def flush(self) -> None:
80
+ pass
81
+
82
+ def seekable(self) -> bool:
83
+ return False
84
+
85
+ def seek(self, n: int, /) -> ta.Any:
86
+ raise TypeError
87
+
88
+
89
+ ##
90
+
91
+
92
+ class NeedMore(lang.Marker):
93
+ pass
94
+
95
+
96
+ class Exited(lang.Marker):
97
+ pass
98
+
99
+
100
+ class Shutdown(BaseException): # noqa
101
+ pass
102
+
103
+
104
+ IoTrampolineTarget: ta.TypeAlias = ta.Callable[[io.BufferedReader], ta.ContextManager[ta.Callable[[], bytes]]]
105
+
106
+
107
+ class IoTrampoline(lang.Abstract):
108
+ def __init__(
109
+ self,
110
+ target: IoTrampolineTarget,
111
+ *,
112
+ buffer_size: int | None = None,
113
+ ) -> None:
114
+ super().__init__()
115
+
116
+ self._target = target
117
+ self._buffer_size = buffer_size
118
+
119
+ def _make_buffered_reader(self, raw: ta.Any) -> io.BufferedReader:
120
+ return io.BufferedReader(
121
+ raw,
122
+ **(dict(buffer_size=self._buffer_size) if self._buffer_size is not None else {}),
123
+ )
124
+
125
+ @abc.abstractmethod
126
+ def close(self, timeout: float | None = None) -> None:
127
+ raise NotImplementedError
128
+
129
+ @abc.abstractmethod
130
+ def __enter__(self) -> ta.Self:
131
+ raise NotImplementedError
132
+
133
+ @abc.abstractmethod
134
+ def __exit__(self, exc_type, exc_val, exc_tb):
135
+ raise NotImplementedError
136
+
137
+ @abc.abstractmethod
138
+ def feed(self, *data: bytes) -> ta.Iterator[bytes]:
139
+ raise NotImplementedError
140
+
141
+
142
+ #
143
+
144
+
145
+ class ThreadIoTrampoline(IoTrampoline):
146
+ def __init__(self, target: IoTrampolineTarget, **kwargs: ta.Any) -> None:
147
+ super().__init__(target, **kwargs)
148
+
149
+ self._in: ConditionDeque[bytes | BaseException] = ConditionDeque()
150
+ self._out: ConditionDeque[
151
+ bytes | # noqa
152
+ type[NeedMore] |
153
+ type[Exited] |
154
+ BaseException
155
+ ] = ConditionDeque()
156
+
157
+ self._proxy = ProxyReadFile(self._read)
158
+
159
+ self._thread = threading.Thread(target=self._thread_proc, daemon=True)
160
+
161
+ #
162
+
163
+ def close(self, timeout: float | None = None) -> None:
164
+ if not self._thread.is_alive():
165
+ return
166
+ self._out.push(Shutdown())
167
+ self._thread.join(timeout)
168
+ if self._thread.is_alive():
169
+ if timeout is not None:
170
+ raise TimeoutError
171
+ else:
172
+ raise RuntimeError('Failed to join thread')
173
+
174
+ #
175
+
176
+ def __enter__(self) -> ta.Self:
177
+ self._thread.start()
178
+ return self
179
+
180
+ def __exit__(self, exc_type, exc_val, exc_tb):
181
+ self.close()
182
+
183
+ #
184
+
185
+ def _read(self, n: int, /) -> bytes | BaseException:
186
+ return self._in.pop(if_empty=lambda: self._out.push(NeedMore))
187
+
188
+ def _thread_proc(self) -> None:
189
+ try:
190
+ with contextlib.closing(self._make_buffered_reader(self._proxy)) as bf: # noqa
191
+ with self._target(bf) as read:
192
+ while out := read():
193
+ self._out.push(out)
194
+ self._out.push(out)
195
+ except BaseException as e:
196
+ self._out.push(e)
197
+ raise
198
+ finally:
199
+ self._out.push(Exited)
200
+
201
+ def feed(self, *data: bytes) -> ta.Iterator[bytes]:
202
+ self._in.push(*data)
203
+ while True:
204
+ e = self._out.pop()
205
+ if e is NeedMore:
206
+ break
207
+ elif isinstance(e, BaseException):
208
+ raise e
209
+ elif e is Exited:
210
+ raise RuntimeError('IO thread exited')
211
+ elif isinstance(e, bytes):
212
+ yield e
213
+ if not e:
214
+ return
215
+ else:
216
+ raise TypeError(e)
217
+
218
+
219
+ #
220
+
221
+
222
+ class ThreadletIoTrampoline(IoTrampoline):
223
+ def __init__(
224
+ self,
225
+ target: IoTrampolineTarget,
226
+ threadlets: tls.Threadlets = tls.GREENLET_THREADLETS,
227
+ ** kwargs: ta.Any,
228
+ ) -> None:
229
+ super().__init__(target, **kwargs)
230
+
231
+ self._proxy = ProxyReadFile(self._read)
232
+ self._tl: tls.Threadlet = threadlets.spawn(self._g_proc)
233
+
234
+ #
235
+
236
+ def close(self, timeout: float | None = None) -> None:
237
+ if self._tl.dead:
238
+ return
239
+ out = self._tl.switch(Shutdown())
240
+ if out is not Exited or not self._tl.dead:
241
+ raise RuntimeError
242
+
243
+ #
244
+
245
+ def __enter__(self) -> ta.Self:
246
+ out = self._tl.switch()
247
+ if out is not NeedMore:
248
+ raise RuntimeError
249
+ return self
250
+
251
+ def __exit__(self, exc_type, exc_val, exc_tb):
252
+ self.close()
253
+
254
+ #
255
+
256
+ def _read(self, n: int, /) -> bytes:
257
+ out = check.not_none(self._tl.parent).switch(NeedMore)
258
+ return out
259
+
260
+ def _g_proc(self) -> ta.Any:
261
+ try:
262
+ with contextlib.closing(self._make_buffered_reader(self._proxy)) as bf: # noqa
263
+ with self._target(bf) as read:
264
+ while out := read():
265
+ e = check.not_none(self._tl.parent).switch(out)
266
+ if e is not NeedMore:
267
+ raise TypeError(e) # noqa
268
+ e = check.not_none(self._tl.parent).switch(out)
269
+ if not isinstance(e, Shutdown):
270
+ raise TypeError(e) # noqa
271
+ return Exited
272
+ except BaseException as e:
273
+ check.not_none(self._tl.parent).throw(e)
274
+ raise
275
+
276
+ def feed(self, *data: bytes) -> ta.Iterator[bytes]:
277
+ i: bytes | type[NeedMore]
278
+ for i in data:
279
+ while True:
280
+ e = self._tl.switch(i)
281
+ i = NeedMore
282
+ if e is NeedMore:
283
+ break
284
+ elif isinstance(e, bytes):
285
+ yield e
286
+ if not e:
287
+ return
288
+ else:
289
+ raise TypeError(e)
File without changes
File without changes
File without changes
@@ -0,0 +1,50 @@
1
+ import typing as ta
2
+
3
+ from omlish import check
4
+ from omlish import dataclasses as dc
5
+ from omlish.funcs import pairs as fps
6
+
7
+ from ..numerics import numerics as nr
8
+ from .formats import MessageFormat
9
+ from .formats import MessageParamsUnpacker
10
+
11
+
12
+ ##
13
+
14
+
15
+ class Message(dc.Case):
16
+ FORMAT: ta.ClassVar[MessageFormat]
17
+ REPLIES: ta.ClassVar[ta.Collection[nr.NumericReply]] = ()
18
+
19
+
20
+ ##
21
+
22
+
23
+ def list_pair_params_unpacker(
24
+ kwarg: str,
25
+ key_param: str,
26
+ value_param: str,
27
+ ) -> MessageParamsUnpacker:
28
+ def forward(params: ta.Mapping[str, str]) -> ta.Mapping[str, ta.Any]:
29
+ out: dict = dict(params)
30
+ ks = out.pop(key_param)
31
+ vs = out.pop(value_param, None)
32
+ if vs is not None:
33
+ out[kwarg] = list(zip(ks, vs, strict=True))
34
+ else:
35
+ out[kwarg] = ks
36
+ return out
37
+
38
+ def backward(kwargs: ta.Mapping[str, ta.Any]) -> ta.Mapping[str, str]:
39
+ out: dict = dict(kwargs)
40
+ ts = out.pop(kwarg)
41
+ is_ts = check.single({isinstance(e, tuple) for e in ts})
42
+ if is_ts:
43
+ ks, vs = zip(*ts)
44
+ out[key_param] = ks
45
+ out[value_param] = vs
46
+ else:
47
+ out[key_param] = ts
48
+ return out
49
+
50
+ return fps.of(forward, backward)
@@ -0,0 +1,92 @@
1
+ import enum
2
+ import typing as ta
3
+
4
+ from omlish import check
5
+ from omlish import dataclasses as dc
6
+ from omlish import lang
7
+ from omlish.funcs import pairs as fps
8
+
9
+
10
+ MessageParamsUnpacker: ta.TypeAlias = fps.FnPair[
11
+ ta.Mapping[str, str], # params
12
+ ta.Mapping[str, ta.Any], # kwargs
13
+ ]
14
+
15
+
16
+ ##
17
+
18
+
19
+ class MessageFormat(dc.Frozen, final=True):
20
+ name: str
21
+
22
+ class Param(dc.Case):
23
+ @classmethod
24
+ def of(cls, obj: ta.Any) -> 'MessageFormat.Param':
25
+ if isinstance(obj, MessageFormat.Param):
26
+ return obj
27
+
28
+ elif isinstance(obj, str):
29
+ s = check.non_empty_str(obj)
30
+
31
+ optional = False
32
+ if s.startswith('?'):
33
+ optional = True
34
+ s = s[1:]
35
+
36
+ arity = MessageFormat.KwargParam.Arity.SINGLE
37
+ if s.startswith('*'):
38
+ arity = MessageFormat.KwargParam.Arity.VARIADIC
39
+ s = s[1:]
40
+
41
+ elif s.startswith(','):
42
+ arity = MessageFormat.KwargParam.Arity.COMMA_LIST
43
+ s = s[1:]
44
+
45
+ return MessageFormat.KwargParam(
46
+ s,
47
+ optional=optional,
48
+ arity=arity,
49
+ )
50
+
51
+ else:
52
+ raise TypeError(obj)
53
+
54
+ class KwargParam(Param):
55
+ name: str = dc.xfield(validate=lang.is_ident)
56
+
57
+ optional: bool = False
58
+
59
+ class Arity(enum.Enum):
60
+ SINGLE = enum.auto() # <foo>
61
+ VARIADIC = enum.auto() # <foo>{ <foo>}
62
+ COMMA_LIST = enum.auto() # <foo>{,<foo>}
63
+
64
+ arity: Arity = Arity.SINGLE
65
+
66
+ class LiteralParam(Param):
67
+ text: str
68
+
69
+ params: ta.Sequence[Param]
70
+
71
+ _: dc.KW_ONLY
72
+
73
+ unpack_params: MessageParamsUnpacker | None = None
74
+
75
+ @dc.init
76
+ def _validate_params(self) -> None:
77
+ kws = [p for p in self.params if isinstance(p, MessageFormat.KwargParam)]
78
+ check.unique(p.name for p in kws)
79
+ check.state(all(p.arity is not MessageFormat.KwargParam.Arity.VARIADIC for p in kws[:-1]))
80
+
81
+ @classmethod
82
+ def of(
83
+ cls,
84
+ name: str,
85
+ *params: ta.Any,
86
+ **kwargs: ta.Any,
87
+ ) -> 'MessageFormat':
88
+ return cls(
89
+ name,
90
+ [MessageFormat.Param.of(p) for p in params],
91
+ **kwargs,
92
+ )