omlish 0.0.0.dev307__py3-none-any.whl → 0.0.0.dev309__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.
- omlish/__about__.py +2 -2
- omlish/asyncs/anyio/subprocesses.py +4 -4
- omlish/asyncs/asyncio/sockets.py +1 -1
- omlish/asyncs/asyncio/subprocesses.py +3 -3
- omlish/asyncs/asyncio/timeouts.py +1 -1
- omlish/daemons/daemon.py +2 -2
- omlish/formats/edn/lexing.py +11 -21
- omlish/formats/edn/parsing.py +11 -31
- omlish/formats/json/stream/lexing.py +17 -2
- omlish/formats/json/stream/parsing.py +14 -5
- omlish/lang/__init__.py +2 -3
- omlish/lang/generators.py +19 -28
- omlish/lite/timeouts.py +5 -5
- omlish/os/pidfiles/pinning.py +1 -1
- omlish/sockets/ports.py +1 -1
- omlish/sockets/wait.py +2 -2
- omlish/specs/jsonrpc/__init__.py +1 -0
- omlish/specs/jsonrpc/conns.py +236 -0
- omlish/specs/jsonrpc/types.py +19 -0
- omlish/subprocesses/async_.py +1 -1
- omlish/subprocesses/run.py +2 -2
- omlish/subprocesses/sync.py +1 -1
- {omlish-0.0.0.dev307.dist-info → omlish-0.0.0.dev309.dist-info}/METADATA +1 -1
- {omlish-0.0.0.dev307.dist-info → omlish-0.0.0.dev309.dist-info}/RECORD +28 -27
- {omlish-0.0.0.dev307.dist-info → omlish-0.0.0.dev309.dist-info}/WHEEL +0 -0
- {omlish-0.0.0.dev307.dist-info → omlish-0.0.0.dev309.dist-info}/entry_points.txt +0 -0
- {omlish-0.0.0.dev307.dist-info → omlish-0.0.0.dev309.dist-info}/licenses/LICENSE +0 -0
- {omlish-0.0.0.dev307.dist-info → omlish-0.0.0.dev309.dist-info}/top_level.txt +0 -0
omlish/__about__.py
CHANGED
@@ -50,11 +50,11 @@ class AnyioSubprocesses(AbstractAsyncSubprocesses):
|
|
50
50
|
stderr = io.BytesIO()
|
51
51
|
tg.start_soon(read_output, proc.stderr, stderr)
|
52
52
|
|
53
|
-
|
54
|
-
|
55
|
-
|
53
|
+
if proc.stdin and run.input is not None:
|
54
|
+
await proc.stdin.send(run.input)
|
55
|
+
await proc.stdin.aclose()
|
56
56
|
|
57
|
-
|
57
|
+
await proc.wait()
|
58
58
|
|
59
59
|
if run.check and proc.returncode != 0:
|
60
60
|
raise subprocess.CalledProcessError(
|
omlish/asyncs/asyncio/sockets.py
CHANGED
@@ -14,7 +14,7 @@ async def asyncio_wait_until_can_connect(
|
|
14
14
|
host: ta.Any = None,
|
15
15
|
port: ta.Any = None,
|
16
16
|
*,
|
17
|
-
timeout:
|
17
|
+
timeout: TimeoutLike = None,
|
18
18
|
on_fail: ta.Optional[ta.Callable[[BaseException], None]] = None,
|
19
19
|
sleep_s: float = .1,
|
20
20
|
exception: ta.Union[ta.Type[BaseException], ta.Tuple[ta.Type[BaseException], ...]] = (Exception,),
|
@@ -131,7 +131,7 @@ class AsyncioProcessCommunicator:
|
|
131
131
|
async def communicate(
|
132
132
|
self,
|
133
133
|
input: ta.Any = None, # noqa
|
134
|
-
timeout:
|
134
|
+
timeout: TimeoutLike = None,
|
135
135
|
) -> Communication:
|
136
136
|
return await asyncio_maybe_timeout(self._communicate(input), timeout)
|
137
137
|
|
@@ -144,7 +144,7 @@ class AsyncioSubprocesses(AbstractAsyncSubprocesses):
|
|
144
144
|
self,
|
145
145
|
proc: asyncio.subprocess.Process,
|
146
146
|
input: ta.Any = None, # noqa
|
147
|
-
timeout:
|
147
|
+
timeout: TimeoutLike = None,
|
148
148
|
) -> ta.Tuple[ta.Optional[bytes], ta.Optional[bytes]]:
|
149
149
|
return await AsyncioProcessCommunicator(proc).communicate(input, timeout) # noqa
|
150
150
|
|
@@ -155,7 +155,7 @@ class AsyncioSubprocesses(AbstractAsyncSubprocesses):
|
|
155
155
|
self,
|
156
156
|
*cmd: str,
|
157
157
|
shell: bool = False,
|
158
|
-
timeout:
|
158
|
+
timeout: TimeoutLike = None,
|
159
159
|
**kwargs: ta.Any,
|
160
160
|
) -> ta.AsyncGenerator[asyncio.subprocess.Process, None]:
|
161
161
|
with self.prepare_and_wrap( *cmd, shell=shell, **kwargs) as (cmd, kwargs): # noqa
|
@@ -15,7 +15,7 @@ AwaitableT = ta.TypeVar('AwaitableT', bound=ta.Awaitable)
|
|
15
15
|
|
16
16
|
def asyncio_maybe_timeout(
|
17
17
|
fut: AwaitableT,
|
18
|
-
timeout:
|
18
|
+
timeout: TimeoutLike = None,
|
19
19
|
) -> AwaitableT:
|
20
20
|
if timeout is not None:
|
21
21
|
fut = asyncio.wait_for(fut, Timeout.of(timeout)()) # type: ignore
|
omlish/daemons/daemon.py
CHANGED
@@ -109,7 +109,7 @@ class Daemon:
|
|
109
109
|
|
110
110
|
def wait_sync(
|
111
111
|
self,
|
112
|
-
timeout: lang.TimeoutLike = lang.Timeout.
|
112
|
+
timeout: lang.TimeoutLike = lang.Timeout.DEFAULT,
|
113
113
|
*,
|
114
114
|
max_tries: int | None = None,
|
115
115
|
) -> None:
|
@@ -140,7 +140,7 @@ class Daemon:
|
|
140
140
|
|
141
141
|
return launcher.launch()
|
142
142
|
|
143
|
-
def launch(self, timeout: lang.TimeoutLike = lang.Timeout.
|
143
|
+
def launch(self, timeout: lang.TimeoutLike = lang.Timeout.DEFAULT) -> None:
|
144
144
|
self.launch_no_wait()
|
145
145
|
|
146
146
|
self.wait_sync(timeout)
|
omlish/formats/edn/lexing.py
CHANGED
@@ -32,6 +32,8 @@ TokenKind: ta.TypeAlias = ta.Literal[
|
|
32
32
|
'HASH_UNDERSCORE',
|
33
33
|
'META',
|
34
34
|
'QUOTE',
|
35
|
+
|
36
|
+
'SPACE',
|
35
37
|
]
|
36
38
|
|
37
39
|
|
@@ -88,7 +90,13 @@ class StreamLexError(Exception):
|
|
88
90
|
|
89
91
|
|
90
92
|
class StreamLexer(GenMachine[str, Token]):
|
91
|
-
def __init__(
|
93
|
+
def __init__(
|
94
|
+
self,
|
95
|
+
*,
|
96
|
+
include_space: bool = False,
|
97
|
+
) -> None:
|
98
|
+
self._include_space = include_space
|
99
|
+
|
92
100
|
self._ofs = 0
|
93
101
|
self._line = 1
|
94
102
|
self._col = 0
|
@@ -155,6 +163,8 @@ class StreamLexer(GenMachine[str, Token]):
|
|
155
163
|
return None
|
156
164
|
|
157
165
|
if c.isspace() or c == ',':
|
166
|
+
if self._include_space:
|
167
|
+
yield self._make_tok('SPACE', c, self.pos)
|
158
168
|
continue
|
159
169
|
|
160
170
|
if c in SINGLE_TOKENS:
|
@@ -303,23 +313,3 @@ class StreamLexer(GenMachine[str, Token]):
|
|
303
313
|
src = self._flip_buf()
|
304
314
|
yield self._make_tok('WORD', src, pos)
|
305
315
|
return self._do_main(c)
|
306
|
-
|
307
|
-
|
308
|
-
##
|
309
|
-
|
310
|
-
|
311
|
-
def test_lex():
|
312
|
-
for s in [
|
313
|
-
'"abc"',
|
314
|
-
'{"a" "b"}',
|
315
|
-
'1',
|
316
|
-
'-1',
|
317
|
-
'{a :b c 420}',
|
318
|
-
'#{a}',
|
319
|
-
]:
|
320
|
-
print(s)
|
321
|
-
with StreamLexer() as lex:
|
322
|
-
for c in [*s, '']:
|
323
|
-
for t in lex(c):
|
324
|
-
print(t)
|
325
|
-
print()
|
omlish/formats/edn/parsing.py
CHANGED
@@ -178,10 +178,15 @@ class StreamParser(GenMachine[Token, ta.Any]):
|
|
178
178
|
else:
|
179
179
|
raise
|
180
180
|
|
181
|
-
|
181
|
+
# ignored
|
182
|
+
|
183
|
+
if tok.kind in ('SPACE', 'COMMENT'):
|
184
|
+
continue
|
182
185
|
|
183
186
|
# scalars
|
184
187
|
|
188
|
+
value: ta.Any
|
189
|
+
|
185
190
|
if tok.kind == 'STRING':
|
186
191
|
value = self._parse_string(tok)
|
187
192
|
|
@@ -197,9 +202,6 @@ class StreamParser(GenMachine[Token, ta.Any]):
|
|
197
202
|
else:
|
198
203
|
value = self._parse_word(tok)
|
199
204
|
|
200
|
-
elif tok.kind == 'COMMENT':
|
201
|
-
continue
|
202
|
-
|
203
205
|
# open
|
204
206
|
|
205
207
|
elif tok.kind == 'LPAREN':
|
@@ -324,8 +326,7 @@ class StreamParser(GenMachine[Token, ta.Any]):
|
|
324
326
|
|
325
327
|
return self._char_maker(c)
|
326
328
|
|
327
|
-
_INT_PAT = re.compile(r'[-+]?(0|[1-9][0-9]*)')
|
328
|
-
_BIGINT_PAT = re.compile(r'[-+]?(0|[1-9][0-9]*)N')
|
329
|
+
_INT_PAT = re.compile(r'[-+]?(0|[1-9][0-9]*)N?')
|
329
330
|
_FLOAT_PAT = re.compile(r'[-+]?(0|[1-9][0-9]*)(\.[0-9]+)?([eE][+-]?(0|[1-9][0-9]*))?M?')
|
330
331
|
|
331
332
|
def _parse_word(self, tok: Token) -> ta.Any:
|
@@ -345,10 +346,11 @@ class StreamParser(GenMachine[Token, ta.Any]):
|
|
345
346
|
# 2r101010, 052, 8r52, 0x2a, 36r16, and 42 are all the same Long.
|
346
347
|
# Floating point numbers are read as Doubles; with M suffix they are read as BigDecimals.
|
347
348
|
# Ratios are supported, e.g. 22/7.
|
348
|
-
|
349
|
+
if src.endswith('N'):
|
350
|
+
return int(src[:-1])
|
349
351
|
|
350
|
-
|
351
|
-
|
352
|
+
else:
|
353
|
+
return int(src)
|
352
354
|
|
353
355
|
elif self._FLOAT_PAT.fullmatch(src):
|
354
356
|
return float(src)
|
@@ -376,25 +378,3 @@ def parse(src: str, **kwargs: ta.Any) -> ta.Any | None:
|
|
376
378
|
if not values:
|
377
379
|
return None
|
378
380
|
return check.single(values)
|
379
|
-
|
380
|
-
|
381
|
-
##
|
382
|
-
|
383
|
-
|
384
|
-
def test_parse():
|
385
|
-
for s in [
|
386
|
-
'"abc"',
|
387
|
-
'"a\\bc"',
|
388
|
-
'{"a" "b"}',
|
389
|
-
'1',
|
390
|
-
'-1',
|
391
|
-
'{a :b c 420}',
|
392
|
-
'#{a}',
|
393
|
-
'(1 #_ 2 3)',
|
394
|
-
'"foo\u1234bar"',
|
395
|
-
'\\x',
|
396
|
-
'\\u1234',
|
397
|
-
]:
|
398
|
-
print(s)
|
399
|
-
print(parse(s))
|
400
|
-
print()
|
@@ -40,7 +40,14 @@ ControlTokenKind: ta.TypeAlias = ta.Literal[
|
|
40
40
|
'COLON',
|
41
41
|
]
|
42
42
|
|
43
|
-
|
43
|
+
SpaceTokenKind: ta.TypeAlias = ta.Literal['SPACE']
|
44
|
+
|
45
|
+
TokenKind: ta.TypeAlias = ta.Union[ # noqa
|
46
|
+
ValueTokenKind,
|
47
|
+
ControlTokenKind,
|
48
|
+
SpaceTokenKind,
|
49
|
+
]
|
50
|
+
|
44
51
|
|
45
52
|
#
|
46
53
|
|
@@ -109,8 +116,10 @@ class JsonStreamLexer(GenMachine[str, Token]):
|
|
109
116
|
self,
|
110
117
|
*,
|
111
118
|
include_raw: bool = False,
|
119
|
+
include_space: bool = False,
|
112
120
|
) -> None:
|
113
121
|
self._include_raw = include_raw
|
122
|
+
self._include_space = include_space
|
114
123
|
|
115
124
|
self._ofs = 0
|
116
125
|
self._line = 1
|
@@ -174,6 +183,8 @@ class JsonStreamLexer(GenMachine[str, Token]):
|
|
174
183
|
return None
|
175
184
|
|
176
185
|
if c.isspace():
|
186
|
+
if self._include_space:
|
187
|
+
yield self._make_tok('SPACE', c, c, self.pos)
|
177
188
|
continue
|
178
189
|
|
179
190
|
if c in CONTROL_TOKENS:
|
@@ -282,7 +293,11 @@ class JsonStreamLexer(GenMachine[str, Token]):
|
|
282
293
|
if c in CONTROL_TOKENS:
|
283
294
|
yield self._make_tok(CONTROL_TOKENS[c], c, c, pos)
|
284
295
|
|
285
|
-
elif
|
296
|
+
elif c.isspace():
|
297
|
+
if self._include_space:
|
298
|
+
yield self._make_tok('SPACE', c, c, self.pos)
|
299
|
+
|
300
|
+
else:
|
286
301
|
self._raise(f'Unexpected character after number: {c}')
|
287
302
|
|
288
303
|
return self._do_main()
|
@@ -102,6 +102,15 @@ class JsonStreamParser(GenMachine[Token, JsonStreamParserEvent]):
|
|
102
102
|
|
103
103
|
#
|
104
104
|
|
105
|
+
def _next_tok(self):
|
106
|
+
while True:
|
107
|
+
tok = yield None
|
108
|
+
|
109
|
+
if tok.kind != 'SPACE':
|
110
|
+
return tok
|
111
|
+
|
112
|
+
#
|
113
|
+
|
105
114
|
def _emit_event(self, v):
|
106
115
|
if not self._stack:
|
107
116
|
return ((v,), self._do_value())
|
@@ -129,7 +138,7 @@ class JsonStreamParser(GenMachine[Token, JsonStreamParserEvent]):
|
|
129
138
|
|
130
139
|
def _do_value(self, *, must_be_present: bool = False):
|
131
140
|
try:
|
132
|
-
tok = yield
|
141
|
+
tok = yield from self._next_tok()
|
133
142
|
except GeneratorExit:
|
134
143
|
if self._stack:
|
135
144
|
raise JsonStreamParseError('Expected value') from None
|
@@ -180,7 +189,7 @@ class JsonStreamParser(GenMachine[Token, JsonStreamParserEvent]):
|
|
180
189
|
|
181
190
|
def _do_object_body(self, *, must_be_present: bool = False):
|
182
191
|
try:
|
183
|
-
tok = yield
|
192
|
+
tok = yield from self._next_tok()
|
184
193
|
except GeneratorExit:
|
185
194
|
raise JsonStreamParseError('Expected object body') from None
|
186
195
|
|
@@ -188,7 +197,7 @@ class JsonStreamParser(GenMachine[Token, JsonStreamParserEvent]):
|
|
188
197
|
k = tok.value
|
189
198
|
|
190
199
|
try:
|
191
|
-
tok = yield
|
200
|
+
tok = yield from self._next_tok()
|
192
201
|
except GeneratorExit:
|
193
202
|
raise JsonStreamParseError('Expected key') from None
|
194
203
|
if tok.kind != 'COLON':
|
@@ -211,7 +220,7 @@ class JsonStreamParser(GenMachine[Token, JsonStreamParserEvent]):
|
|
211
220
|
|
212
221
|
def _do_after_pair(self):
|
213
222
|
try:
|
214
|
-
tok = yield
|
223
|
+
tok = yield from self._next_tok()
|
215
224
|
except GeneratorExit:
|
216
225
|
raise JsonStreamParseError('Expected continuation') from None
|
217
226
|
|
@@ -244,7 +253,7 @@ class JsonStreamParser(GenMachine[Token, JsonStreamParserEvent]):
|
|
244
253
|
|
245
254
|
def _do_after_element(self):
|
246
255
|
try:
|
247
|
-
tok = yield
|
256
|
+
tok = yield from self._next_tok()
|
248
257
|
except GeneratorExit:
|
249
258
|
raise JsonStreamParseError('Expected continuation') from None
|
250
259
|
|
omlish/lang/__init__.py
CHANGED
@@ -184,12 +184,11 @@ from .functions import ( # noqa
|
|
184
184
|
)
|
185
185
|
|
186
186
|
from .generators import ( # noqa
|
187
|
-
CoroutineGenerator,
|
188
|
-
Generator,
|
189
187
|
GeneratorLike,
|
190
188
|
GeneratorMappedIterator,
|
191
189
|
autostart,
|
192
|
-
|
190
|
+
capture_coroutine,
|
191
|
+
capture_generator,
|
193
192
|
genmap,
|
194
193
|
nextgen,
|
195
194
|
)
|
omlish/lang/generators.py
CHANGED
@@ -2,6 +2,7 @@ import abc
|
|
2
2
|
import functools
|
3
3
|
import typing as ta
|
4
4
|
|
5
|
+
from .classes.restrict import Abstract
|
5
6
|
from .maybes import Maybe
|
6
7
|
from .maybes import empty
|
7
8
|
from .maybes import just
|
@@ -79,15 +80,29 @@ def adapt_generator_like(gl):
|
|
79
80
|
##
|
80
81
|
|
81
82
|
|
82
|
-
class
|
83
|
+
class AbstractGeneratorCapture(Abstract, ta.Generic[O, I, R]):
|
83
84
|
def __init__(self, g: ta.Generator[O, I, R]) -> None:
|
84
85
|
super().__init__()
|
86
|
+
|
85
87
|
self._g = g
|
86
88
|
|
87
89
|
@property
|
88
90
|
def g(self) -> ta.Generator[O, I, R]:
|
89
91
|
return self._g
|
90
92
|
|
93
|
+
#
|
94
|
+
|
95
|
+
def close(self) -> None:
|
96
|
+
self._g.close()
|
97
|
+
|
98
|
+
def __enter__(self) -> ta.Self:
|
99
|
+
return self
|
100
|
+
|
101
|
+
def __exit__(self, exc_type, exc_val, exc_tb):
|
102
|
+
self._g.close()
|
103
|
+
|
104
|
+
|
105
|
+
class GeneratorCapture(AbstractGeneratorCapture[O, I, R], ta.Generator[O, I, R]):
|
91
106
|
value: R
|
92
107
|
|
93
108
|
def __iter__(self):
|
@@ -114,35 +129,11 @@ class Generator(ta.Generator[O, I, R]):
|
|
114
129
|
self.value = e.value
|
115
130
|
raise
|
116
131
|
|
117
|
-
def close(self):
|
118
|
-
self._g.close()
|
119
132
|
|
133
|
+
capture_generator = GeneratorCapture
|
120
134
|
|
121
|
-
##
|
122
|
-
|
123
|
-
|
124
|
-
class CoroutineGenerator(ta.Generic[O, I, R]):
|
125
|
-
def __init__(self, g: ta.Generator[O, I, R]) -> None:
|
126
|
-
super().__init__()
|
127
|
-
self._g = g
|
128
|
-
|
129
|
-
@property
|
130
|
-
def g(self) -> ta.Generator[O, I, R]:
|
131
|
-
return self._g
|
132
|
-
|
133
|
-
#
|
134
|
-
|
135
|
-
def close(self) -> None:
|
136
|
-
self._g.close()
|
137
|
-
|
138
|
-
def __enter__(self) -> ta.Self:
|
139
|
-
return self
|
140
|
-
|
141
|
-
def __exit__(self, exc_type, exc_val, exc_tb):
|
142
|
-
self._g.close()
|
143
|
-
|
144
|
-
#
|
145
135
|
|
136
|
+
class CoroutineGeneratorCapture(AbstractGeneratorCapture[O, I, R]):
|
146
137
|
class Output(ta.NamedTuple, ta.Generic[T]):
|
147
138
|
v: T
|
148
139
|
|
@@ -192,7 +183,7 @@ class CoroutineGenerator(ta.Generic[O, I, R]):
|
|
192
183
|
return self.Yield(o)
|
193
184
|
|
194
185
|
|
195
|
-
|
186
|
+
capture_coroutine = CoroutineGeneratorCapture
|
196
187
|
|
197
188
|
|
198
189
|
##
|
omlish/lite/timeouts.py
CHANGED
@@ -8,7 +8,7 @@ import time
|
|
8
8
|
import typing as ta
|
9
9
|
|
10
10
|
|
11
|
-
TimeoutLike = ta.Union['Timeout', ta.Type['Timeout.
|
11
|
+
TimeoutLike = ta.Union['Timeout', ta.Type['Timeout.DEFAULT'], ta.Iterable['TimeoutLike'], float, None] # ta.TypeAlias
|
12
12
|
|
13
13
|
|
14
14
|
##
|
@@ -54,7 +54,7 @@ class Timeout(abc.ABC):
|
|
54
54
|
|
55
55
|
#
|
56
56
|
|
57
|
-
class
|
57
|
+
class DEFAULT: # Noqa
|
58
58
|
def __new__(cls, *args, **kwargs): # noqa
|
59
59
|
raise TypeError
|
60
60
|
|
@@ -65,7 +65,7 @@ class Timeout(abc.ABC):
|
|
65
65
|
@classmethod
|
66
66
|
def of(
|
67
67
|
cls,
|
68
|
-
obj:
|
68
|
+
obj: TimeoutLike,
|
69
69
|
default: ta.Union[TimeoutLike, ta.Type[_NOT_SPECIFIED]] = _NOT_SPECIFIED,
|
70
70
|
) -> 'Timeout':
|
71
71
|
if obj is None:
|
@@ -80,8 +80,8 @@ class Timeout(abc.ABC):
|
|
80
80
|
elif isinstance(obj, ta.Iterable):
|
81
81
|
return CompositeTimeout(*[Timeout.of(c) for c in obj])
|
82
82
|
|
83
|
-
elif obj is Timeout.
|
84
|
-
if default is Timeout._NOT_SPECIFIED or default is Timeout.
|
83
|
+
elif obj is Timeout.DEFAULT:
|
84
|
+
if default is Timeout._NOT_SPECIFIED or default is Timeout.DEFAULT:
|
85
85
|
raise RuntimeError('Must specify a default timeout')
|
86
86
|
|
87
87
|
else:
|
omlish/os/pidfiles/pinning.py
CHANGED
@@ -64,7 +64,7 @@ class PidfilePinner(abc.ABC):
|
|
64
64
|
self,
|
65
65
|
path: str,
|
66
66
|
*,
|
67
|
-
timeout:
|
67
|
+
timeout: TimeoutLike = None,
|
68
68
|
inheritable: bool = False, # Present to match Pidfile kwargs for convenience, but enforced to be False.
|
69
69
|
**kwargs: ta.Any,
|
70
70
|
) -> ta.Iterator[int]:
|
omlish/sockets/ports.py
CHANGED
omlish/sockets/wait.py
CHANGED
@@ -14,7 +14,7 @@ from ..lite.timeouts import TimeoutLike
|
|
14
14
|
def socket_can_connect(
|
15
15
|
address: ta.Any,
|
16
16
|
*,
|
17
|
-
timeout:
|
17
|
+
timeout: TimeoutLike = None,
|
18
18
|
on_fail: ta.Optional[ta.Callable[[BaseException], None]] = None,
|
19
19
|
exception: ta.Union[ta.Type[BaseException], ta.Tuple[ta.Type[BaseException], ...]] = (ConnectionRefusedError,),
|
20
20
|
) -> bool:
|
@@ -36,7 +36,7 @@ def socket_can_connect(
|
|
36
36
|
def socket_wait_until_can_connect(
|
37
37
|
address: ta.Any,
|
38
38
|
*,
|
39
|
-
timeout:
|
39
|
+
timeout: TimeoutLike = None,
|
40
40
|
on_fail: ta.Optional[ta.Callable[[BaseException], None]] = None,
|
41
41
|
sleep_s: float = .1,
|
42
42
|
exception: ta.Union[ta.Type[BaseException], ta.Tuple[ta.Type[BaseException], ...]] = (ConnectionRefusedError,),
|
omlish/specs/jsonrpc/__init__.py
CHANGED
@@ -0,0 +1,236 @@
|
|
1
|
+
import builtins
|
2
|
+
import functools
|
3
|
+
import json
|
4
|
+
import typing as ta
|
5
|
+
import uuid
|
6
|
+
|
7
|
+
import anyio.abc
|
8
|
+
|
9
|
+
from ... import check
|
10
|
+
from ... import lang
|
11
|
+
from ... import marshal as msh
|
12
|
+
from ...asyncs import anyio as aiu
|
13
|
+
from ...io.buffers import DelimitingBuffer
|
14
|
+
from .types import Error
|
15
|
+
from .types import Id
|
16
|
+
from .types import Message
|
17
|
+
from .types import NotSpecified
|
18
|
+
from .types import Object
|
19
|
+
from .types import Request
|
20
|
+
from .types import Response
|
21
|
+
from .types import detect_message_type
|
22
|
+
from .types import notification
|
23
|
+
from .types import request
|
24
|
+
|
25
|
+
|
26
|
+
##
|
27
|
+
|
28
|
+
|
29
|
+
@lang.cached_function
|
30
|
+
def _create_id() -> str:
|
31
|
+
return str(uuid.uuid4())
|
32
|
+
|
33
|
+
|
34
|
+
class JsonrpcConnection:
|
35
|
+
def __init__(
|
36
|
+
self,
|
37
|
+
tg: anyio.abc.TaskGroup,
|
38
|
+
stream: anyio.abc.ByteStream,
|
39
|
+
*,
|
40
|
+
request_handler: ta.Callable[['JsonrpcConnection', Request], ta.Awaitable[None]] | None = None,
|
41
|
+
notification_handler: ta.Callable[['JsonrpcConnection', Request], ta.Awaitable[None]] | None = None,
|
42
|
+
default_timeout: float | None = 30.,
|
43
|
+
) -> None:
|
44
|
+
super().__init__()
|
45
|
+
|
46
|
+
self._tg = tg
|
47
|
+
self._stream = stream
|
48
|
+
self._request_handler = request_handler
|
49
|
+
self._notification_handler = notification_handler
|
50
|
+
self._default_timeout = default_timeout
|
51
|
+
|
52
|
+
self._buf = DelimitingBuffer(b'\n')
|
53
|
+
self._response_futures_by_id: dict[Id, aiu.Future[Response]] = {}
|
54
|
+
self._send_lock = anyio.Lock()
|
55
|
+
self._shutdown_event = anyio.Event()
|
56
|
+
self._received_eof = False
|
57
|
+
|
58
|
+
#
|
59
|
+
|
60
|
+
class Error(Exception):
|
61
|
+
"""Base class for JSON-RPC related errors."""
|
62
|
+
|
63
|
+
class TimeoutError(Error, builtins.TimeoutError): # noqa
|
64
|
+
"""Raised when a request times out."""
|
65
|
+
|
66
|
+
class ConnectionError(Error, builtins.ConnectionError): # noqa
|
67
|
+
"""Raised when there are connection-related issues."""
|
68
|
+
|
69
|
+
class ProtocolError(Error):
|
70
|
+
"""Raised when there are protocol-related issues."""
|
71
|
+
|
72
|
+
#
|
73
|
+
|
74
|
+
async def __aenter__(self) -> 'JsonrpcConnection':
|
75
|
+
await self._tg.start(self._receive_loop)
|
76
|
+
return self
|
77
|
+
|
78
|
+
async def __aexit__(self, exc_type: type[BaseException] | None, *_: object) -> None:
|
79
|
+
self._shutdown_event.set()
|
80
|
+
|
81
|
+
##
|
82
|
+
|
83
|
+
async def _handle_message(self, msg: Message) -> None:
|
84
|
+
if isinstance(msg, Response):
|
85
|
+
msg_id = msg.id
|
86
|
+
try:
|
87
|
+
resp_fut = self._response_futures_by_id[msg_id]
|
88
|
+
except KeyError:
|
89
|
+
raise NotImplementedError from None
|
90
|
+
resp_fut.set_value(msg)
|
91
|
+
|
92
|
+
elif isinstance(msg, Request):
|
93
|
+
if msg.is_notification:
|
94
|
+
if (mh := self._notification_handler) is not None:
|
95
|
+
await mh(self, msg)
|
96
|
+
|
97
|
+
else: # noqa
|
98
|
+
if (rh := self._request_handler) is not None:
|
99
|
+
await rh(self, msg)
|
100
|
+
|
101
|
+
else:
|
102
|
+
raise TypeError(msg)
|
103
|
+
|
104
|
+
#
|
105
|
+
|
106
|
+
CLOSED_EXCEPTIONS: ta.ClassVar[tuple[type[Exception], ...]] = (
|
107
|
+
anyio.ClosedResourceError,
|
108
|
+
anyio.EndOfStream,
|
109
|
+
)
|
110
|
+
|
111
|
+
ERROR_EXCEPTIONS: ta.ClassVar[tuple[type[Exception], ...]] = (
|
112
|
+
OSError,
|
113
|
+
anyio.BrokenResourceError,
|
114
|
+
)
|
115
|
+
|
116
|
+
async def _receive_message_batch(self) -> list[Message] | None:
|
117
|
+
check.state(not self._received_eof)
|
118
|
+
|
119
|
+
if self._shutdown_event.is_set():
|
120
|
+
return None
|
121
|
+
|
122
|
+
while True:
|
123
|
+
maybe_shutdown: lang.Maybe[bool]
|
124
|
+
maybe_data: lang.Maybe[lang.Outcome[bytes]]
|
125
|
+
(
|
126
|
+
maybe_shutdown,
|
127
|
+
maybe_data,
|
128
|
+
) = await aiu.gather( # type: ignore
|
129
|
+
self._shutdown_event.wait,
|
130
|
+
functools.partial(lang.acapture, self._stream.receive),
|
131
|
+
take_first=True,
|
132
|
+
)
|
133
|
+
|
134
|
+
if self._shutdown_event.is_set():
|
135
|
+
return None
|
136
|
+
|
137
|
+
try:
|
138
|
+
data = maybe_data.must().unwrap()
|
139
|
+
except self.CLOSED_EXCEPTIONS:
|
140
|
+
data = b''
|
141
|
+
except self.ERROR_EXCEPTIONS as e:
|
142
|
+
raise JsonrpcConnection.ConnectionError('Failed to receive message') from e
|
143
|
+
|
144
|
+
if not data:
|
145
|
+
self._received_eof = True
|
146
|
+
|
147
|
+
lines = list(self._buf.feed(data))
|
148
|
+
if lines:
|
149
|
+
break
|
150
|
+
|
151
|
+
if not data:
|
152
|
+
return None
|
153
|
+
|
154
|
+
msgs: list[Message] = []
|
155
|
+
for line in lines:
|
156
|
+
if isinstance(line, DelimitingBuffer.Incomplete):
|
157
|
+
raise ConnectionError('Received incomplete message')
|
158
|
+
|
159
|
+
try:
|
160
|
+
dct = json.loads(line.decode('utf-8'))
|
161
|
+
except (UnicodeDecodeError, json.JSONDecodeError) as e:
|
162
|
+
raise JsonrpcConnection.ProtocolError from e
|
163
|
+
|
164
|
+
mcls = detect_message_type(dct)
|
165
|
+
try:
|
166
|
+
msg = msh.unmarshal(dct, mcls)
|
167
|
+
except Exception as e:
|
168
|
+
raise JsonrpcConnection.ProtocolError from e
|
169
|
+
|
170
|
+
msgs.append(msg)
|
171
|
+
|
172
|
+
return msgs
|
173
|
+
|
174
|
+
async def _receive_loop(
|
175
|
+
self,
|
176
|
+
*,
|
177
|
+
task_status: anyio.abc.TaskStatus[ta.Any] = anyio.TASK_STATUS_IGNORED,
|
178
|
+
) -> None:
|
179
|
+
task_status.started()
|
180
|
+
|
181
|
+
while not self._shutdown_event.is_set():
|
182
|
+
msgs = await self._receive_message_batch()
|
183
|
+
if msgs is None:
|
184
|
+
break
|
185
|
+
|
186
|
+
for msg in msgs:
|
187
|
+
await self._handle_message(msg)
|
188
|
+
|
189
|
+
##
|
190
|
+
|
191
|
+
async def send_message(self, msg: Message) -> None:
|
192
|
+
async with self._send_lock:
|
193
|
+
try:
|
194
|
+
await self._stream.send(json.dumps(msh.marshal(msg)).encode() + b'\n')
|
195
|
+
except self.ERROR_EXCEPTIONS as e:
|
196
|
+
raise ConnectionError('Failed to send message') from e
|
197
|
+
|
198
|
+
#
|
199
|
+
|
200
|
+
async def request(
|
201
|
+
self,
|
202
|
+
method: str,
|
203
|
+
params: Object | None = None,
|
204
|
+
*,
|
205
|
+
timeout: lang.TimeoutLike | None = lang.Timeout.DEFAULT,
|
206
|
+
) -> ta.Any:
|
207
|
+
msg_id = _create_id()
|
208
|
+
req = request(msg_id, method, params)
|
209
|
+
|
210
|
+
fut = aiu.create_future[Response]()
|
211
|
+
self._response_futures_by_id[msg_id] = fut
|
212
|
+
|
213
|
+
try:
|
214
|
+
await self.send_message(req)
|
215
|
+
|
216
|
+
timeout_val = lang.Timeout.of(timeout, self._default_timeout)
|
217
|
+
try:
|
218
|
+
with anyio.fail_after(timeout_val.or_(None)):
|
219
|
+
await fut
|
220
|
+
except TimeoutError as e:
|
221
|
+
raise JsonrpcConnection.TimeoutError(f'Request timed out after {timeout_val} seconds') from e
|
222
|
+
|
223
|
+
response = fut.outcome.must().unwrap()
|
224
|
+
|
225
|
+
if response.error is not NotSpecified:
|
226
|
+
error = ta.cast(Error, response.error)
|
227
|
+
raise JsonrpcConnection.Error(f'Error {error.code}: {error.message}')
|
228
|
+
|
229
|
+
return response.result
|
230
|
+
|
231
|
+
finally:
|
232
|
+
self._response_futures_by_id.pop(msg_id, None) # noqa
|
233
|
+
|
234
|
+
async def notify(self, method: str, params: Object | None = None) -> None:
|
235
|
+
msg = notification(method, params)
|
236
|
+
await self.send_message(msg)
|
omlish/specs/jsonrpc/types.py
CHANGED
@@ -18,6 +18,8 @@ from ... import lang
|
|
18
18
|
from ... import marshal as msh
|
19
19
|
|
20
20
|
|
21
|
+
T = ta.TypeVar('T')
|
22
|
+
|
21
23
|
NUMBER_TYPES: tuple[type, ...] = (int, float)
|
22
24
|
Number: ta.TypeAlias = int | float
|
23
25
|
|
@@ -44,6 +46,11 @@ def is_not_specified(v: ta.Any) -> bool:
|
|
44
46
|
return v is NotSpecified
|
45
47
|
|
46
48
|
|
49
|
+
def check_not_not_specified(v: T | type[NotSpecified]) -> T:
|
50
|
+
check.arg(not is_not_specified(v))
|
51
|
+
return ta.cast(T, v)
|
52
|
+
|
53
|
+
|
47
54
|
##
|
48
55
|
|
49
56
|
|
@@ -87,10 +94,22 @@ class Response(lang.Final):
|
|
87
94
|
|
88
95
|
_: dc.KW_ONLY
|
89
96
|
|
97
|
+
#
|
98
|
+
|
90
99
|
result: ta.Any = dc.field(default=NotSpecified)
|
91
100
|
error: ta.Union['Error', type[NotSpecified]] = dc.field(default=NotSpecified)
|
92
101
|
dc.validate(lambda self: is_not_specified(self.result) ^ is_not_specified(self.error))
|
93
102
|
|
103
|
+
@property
|
104
|
+
def is_result(self) -> bool:
|
105
|
+
return not is_not_specified(self.result)
|
106
|
+
|
107
|
+
@property
|
108
|
+
def is_error(self) -> bool:
|
109
|
+
return not is_not_specified(self.error)
|
110
|
+
|
111
|
+
#
|
112
|
+
|
94
113
|
jsonrpc: str = dc.field(default=VERSION)
|
95
114
|
dc.validate(lambda self: self.jsonrpc == VERSION)
|
96
115
|
|
omlish/subprocesses/async_.py
CHANGED
@@ -22,7 +22,7 @@ class AbstractAsyncSubprocesses(BaseSubprocesses):
|
|
22
22
|
self,
|
23
23
|
*cmd: str,
|
24
24
|
input: ta.Any = None, # noqa
|
25
|
-
timeout:
|
25
|
+
timeout: TimeoutLike = None,
|
26
26
|
check: bool = False,
|
27
27
|
capture_output: ta.Optional[bool] = None,
|
28
28
|
**kwargs: ta.Any,
|
omlish/subprocesses/run.py
CHANGED
@@ -31,7 +31,7 @@ class SubprocessRunOutput(ta.Generic[T]):
|
|
31
31
|
class SubprocessRun:
|
32
32
|
cmd: ta.Sequence[str]
|
33
33
|
input: ta.Any = None
|
34
|
-
timeout:
|
34
|
+
timeout: TimeoutLike = None
|
35
35
|
check: bool = False
|
36
36
|
capture_output: ta.Optional[bool] = None
|
37
37
|
kwargs: ta.Optional[ta.Mapping[str, ta.Any]] = None
|
@@ -67,7 +67,7 @@ class SubprocessRun:
|
|
67
67
|
cls,
|
68
68
|
*cmd: str,
|
69
69
|
input: ta.Any = None, # noqa
|
70
|
-
timeout:
|
70
|
+
timeout: TimeoutLike = None,
|
71
71
|
check: bool = False, # noqa
|
72
72
|
capture_output: ta.Optional[bool] = None,
|
73
73
|
**kwargs: ta.Any,
|
omlish/subprocesses/sync.py
CHANGED
@@ -28,7 +28,7 @@ class AbstractSubprocesses(BaseSubprocesses, abc.ABC):
|
|
28
28
|
self,
|
29
29
|
*cmd: str,
|
30
30
|
input: ta.Any = None, # noqa
|
31
|
-
timeout:
|
31
|
+
timeout: TimeoutLike = None,
|
32
32
|
check: bool = False,
|
33
33
|
capture_output: ta.Optional[bool] = None,
|
34
34
|
**kwargs: ta.Any,
|
@@ -1,5 +1,5 @@
|
|
1
1
|
omlish/.manifests.json,sha256=orgsRvtpHu8tdhaCvlP9v3P495OJopYYiHKjK68WtWg,8587
|
2
|
-
omlish/__about__.py,sha256=
|
2
|
+
omlish/__about__.py,sha256=AMalr2v0ecBESsAeIHXFu3Gev9RWMipfQsSGjc671qA,3478
|
3
3
|
omlish/__init__.py,sha256=SsyiITTuK0v74XpKV8dqNaCmjOlan1JZKrHQv5rWKPA,253
|
4
4
|
omlish/c3.py,sha256=rer-TPOFDU6fYq_AWio_AmA-ckZ8JDY5shIzQ_yXfzA,8414
|
5
5
|
omlish/cached.py,sha256=MLap_p0rdGoDIMVhXVHm1tsbcWobJF0OanoodV03Ju8,542
|
@@ -102,16 +102,16 @@ omlish/asyncs/anyio/backends.py,sha256=jJIymWoiedaEJJm82gvKiJ41EWLQZ-bcyNHpbDpKK
|
|
102
102
|
omlish/asyncs/anyio/futures.py,sha256=Nm1gLerZEnHk-rlsmr0UfK168IWIK6zA8EebZFtoY_E,2052
|
103
103
|
omlish/asyncs/anyio/signals.py,sha256=ySSut5prdnoy0-5Ws5V1M4cC2ON_vY550vU10d2NHk8,893
|
104
104
|
omlish/asyncs/anyio/streams.py,sha256=Zum2qd1t3EiH6yzGWFwxFw79m-IH2VY5sTUTiluFfIY,2164
|
105
|
-
omlish/asyncs/anyio/subprocesses.py,sha256=
|
105
|
+
omlish/asyncs/anyio/subprocesses.py,sha256=nyl1A9z3rymxQMvIekWHU3IAiKBu1CcEqm-Ag1cGRPY,3018
|
106
106
|
omlish/asyncs/anyio/sync.py,sha256=ZmSNhSsEkPwlXThrpefhtVTxw4GJ9F0P-yKyo5vbbSk,1574
|
107
107
|
omlish/asyncs/anyio/utils.py,sha256=X2Rz1DGrCJ0zkt1O5cHoMRaYKTPndBj6dzLhb09mVtE,1672
|
108
108
|
omlish/asyncs/asyncio/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
109
109
|
omlish/asyncs/asyncio/all.py,sha256=u2JpMEs-0AJ0Vd8yU10HvWD8rfKxdFfMiwBu2oDeuuQ,313
|
110
110
|
omlish/asyncs/asyncio/channels.py,sha256=X3S951YTjTRDguMSQRlfu74mPuWkNd2ZEUWboLY58-M,1079
|
111
|
-
omlish/asyncs/asyncio/sockets.py,sha256=
|
111
|
+
omlish/asyncs/asyncio/sockets.py,sha256=QdXWswN9p9jOlaXUSYnCQZtwu1_jSQNWBiKPt6bws6o,1258
|
112
112
|
omlish/asyncs/asyncio/streams.py,sha256=J_d1hgX4Mx9SfyW4DjOzh91PqzZmjOtiIB95ytF8Ygw,1009
|
113
|
-
omlish/asyncs/asyncio/subprocesses.py,sha256=
|
114
|
-
omlish/asyncs/asyncio/timeouts.py,sha256=
|
113
|
+
omlish/asyncs/asyncio/subprocesses.py,sha256=Mvy5cXHbY-JB5Yl57G05c2O7aEMAjSe29Ed_J63pvx0,6896
|
114
|
+
omlish/asyncs/asyncio/timeouts.py,sha256=c-DhZi0yFXhJ6NtHa4EhB1Vrr1QDVd-7HBRkr96Q2So,446
|
115
115
|
omlish/asyncs/asyncio/utils.py,sha256=mDjYNm1cylUhQ8slWXwdPoXasuWfafjzu78GHt2Mdig,2437
|
116
116
|
omlish/asyncs/bluelet/LICENSE,sha256=VHf3oPQihOHnWyIR8LcXX0dpONa1lgyJnjWC2qVuRR0,559
|
117
117
|
omlish/asyncs/bluelet/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -195,7 +195,7 @@ omlish/configs/processing/names.py,sha256=weHmaTclzgM9lUn3aBtw-kwZ3mc2N-CZlFg3Kd
|
|
195
195
|
omlish/configs/processing/rewriting.py,sha256=v7PfHtuTn5v_5Y6Au7oMN2Z0nxAMy1iYyO5CXnTvZhs,4226
|
196
196
|
omlish/configs/processing/strings.py,sha256=qFS2oh6z02IaM_q4lTKLdufzkJqAJ6J-Qjrz5S-QJoM,826
|
197
197
|
omlish/daemons/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
198
|
-
omlish/daemons/daemon.py,sha256=
|
198
|
+
omlish/daemons/daemon.py,sha256=pUwomapIrUwXLnov9jlA5EU1vp4qEYcIiUxKD3SQyVo,3479
|
199
199
|
omlish/daemons/launching.py,sha256=sNOYW939IGI4ZlLQ0bKxzXj6EyeOiwV7Upqhd5XfoHc,3747
|
200
200
|
omlish/daemons/reparent.py,sha256=7uJ9oPGt9Ud7uA8bDl_SHcuqjcsmXa3kkjp9jf29wOw,585
|
201
201
|
omlish/daemons/services.py,sha256=YYp2SMkJ71WgzOcYSXjWHeAyKKxu3j1dfuJvWkl0Dgw,3492
|
@@ -321,8 +321,8 @@ omlish/formats/xml.py,sha256=VJfqHR60dhAtjeG8WXFMozFqesTBSGvv264d67eDFXc,3514
|
|
321
321
|
omlish/formats/yaml.py,sha256=jGPQlTE0vSV-p0O7TJRNlf6o1uq4gx8PrHZe1ApJ_o8,7386
|
322
322
|
omlish/formats/edn/__init__.py,sha256=H3q5B-dibXvQV8pmuWizTo6Xk75M7M0M7VPCLt86rpo,195
|
323
323
|
omlish/formats/edn/codec.py,sha256=k6-Ra3P3Rlv6JA69-jPLI4nCe5XVes_QJbcsj5DYzMM,454
|
324
|
-
omlish/formats/edn/lexing.py,sha256=
|
325
|
-
omlish/formats/edn/parsing.py,sha256=
|
324
|
+
omlish/formats/edn/lexing.py,sha256=LaIaGql9NtRlgi6bs4XhZ-wtabiUs99PoYN7_yAKMNE,6892
|
325
|
+
omlish/formats/edn/parsing.py,sha256=Y1CBxtdlbnn5zwU5nlxX3uw17u2POST8tabtVV1q0X4,9835
|
326
326
|
omlish/formats/edn/values.py,sha256=jf0g88KJIMALxcuH51SoaMWg1HqTUqc1ugldmyyXWoc,3707
|
327
327
|
omlish/formats/ini/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
328
328
|
omlish/formats/ini/codec.py,sha256=omuFg0kiDksv8rRlWd_v32ebzEcKlgmiPgGID3bRi2M,631
|
@@ -345,8 +345,8 @@ omlish/formats/json/backends/ujson.py,sha256=BNJCU4kluGHdqTUKLJEuHhE2m2TmqR7HEN2
|
|
345
345
|
omlish/formats/json/stream/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
346
346
|
omlish/formats/json/stream/building.py,sha256=SGbExmaerqOEiNSom2AERlpyXTj4dpM0QbMW-2WWM2o,2550
|
347
347
|
omlish/formats/json/stream/errors.py,sha256=c8M8UAYmIZ-vWZLeKD2jMj4EDCJbr9QR8Jq_DyHjujQ,43
|
348
|
-
omlish/formats/json/stream/lexing.py,sha256=
|
349
|
-
omlish/formats/json/stream/parsing.py,sha256=
|
348
|
+
omlish/formats/json/stream/lexing.py,sha256=0XbkpKm4rmn5DLRyqnVpyvBXMi_MjVEI1k6-TIgQWRM,7208
|
349
|
+
omlish/formats/json/stream/parsing.py,sha256=AXsg0N5s0jEvdfEQrzprplZDNkB62l6Q3Pv8rIx3984,6454
|
350
350
|
omlish/formats/json/stream/rendering.py,sha256=uuJc__MR0G5kypYMAAudBNjBfiIzA_GGli-DWT90428,3730
|
351
351
|
omlish/formats/json/stream/utils.py,sha256=UhBRuWbb25wrdQWl8Ttq7xGRLoa329TvNdecGCZxgzg,1197
|
352
352
|
omlish/formats/json5/Json5.g4,sha256=ZUmgJPvj8lSMUD_v3wijp10ZQExYB5mu5Q089dYEJSU,2389
|
@@ -470,7 +470,7 @@ omlish/iterators/iterators.py,sha256=RxW35yQ5ed8vBQ22IqpDXFx-i5JiLQdp7-pkMZXhJJ8
|
|
470
470
|
omlish/iterators/recipes.py,sha256=wOwOZg-zWG9Zc3wcAxJFSe2rtavVBYwZOfG09qYEx_4,472
|
471
471
|
omlish/iterators/tools.py,sha256=c4hArZEVV8y9_dFfmRwakusv1cWJLT4MkTkGRjnGN5U,2556
|
472
472
|
omlish/iterators/unique.py,sha256=Nw0pSaNEcHAkve0ugfLPvJcirDOn9ECyC5wIL8JlJKI,1395
|
473
|
-
omlish/lang/__init__.py,sha256=
|
473
|
+
omlish/lang/__init__.py,sha256=yJvuoESt6-nZckXYcHctZYEnHCRCjQ2SkRV3ctUljPI,5856
|
474
474
|
omlish/lang/attrs.py,sha256=i7euRF81uNF8QDmUVXSK_BtqLGshaMi4VVdUnMjiMwg,5050
|
475
475
|
omlish/lang/casing.py,sha256=cFUlbDdXLhwnWwcYx4qnM5c4zGX7hIRUfcjiZbxUD28,4636
|
476
476
|
omlish/lang/clsdct.py,sha256=HAGIvBSbCefzRjXriwYSBLO7QHKRv2UsE78jixOb-fA,1828
|
@@ -481,7 +481,7 @@ omlish/lang/datetimes.py,sha256=mrTtA67JYpfQwSlzdPcBtvm6dAyYM_dXNnlxFwFQH0M,228
|
|
481
481
|
omlish/lang/descriptors.py,sha256=zBtgO9LjdSTGHNUgiIqswh78WOVoGH6KzS0NbgB1Wls,6572
|
482
482
|
omlish/lang/enums.py,sha256=F9tflHfaAoV2MpyuhZzpfX9-H55M3zNa9hCszsngEo8,111
|
483
483
|
omlish/lang/functions.py,sha256=51CoKtH_-CXUsKvtCexaR3OLZOtIwSdv4f4DtGBZdpA,6029
|
484
|
-
omlish/lang/generators.py,sha256=
|
484
|
+
omlish/lang/generators.py,sha256=yd3ebG2LlA3XQImP8rplt6tSToXwMxhlGRGCkdJ87ME,5230
|
485
485
|
omlish/lang/imports.py,sha256=y9W9Y-d_cQ35QCLuSIPoa6vnEqSErFCz8b-34IH128U,10552
|
486
486
|
omlish/lang/iterables.py,sha256=HOjcxOwyI5bBApDLsxRAGGhTTmw7fdZl2kEckxRVl-0,1994
|
487
487
|
omlish/lang/maybes.py,sha256=pb1YrxmpXy-hWKmWR89GxXqZq1MoUD1uuTaTX30peh0,3697
|
@@ -529,7 +529,7 @@ omlish/lite/resources.py,sha256=YNSmX1Ohck1aoWRs55a-o5ChVbFJIQhtbqE-XwF55Oc,326
|
|
529
529
|
omlish/lite/runtime.py,sha256=XQo408zxTdJdppUZqOWHyeUR50VlCpNIExNGHz4U6O4,459
|
530
530
|
omlish/lite/secrets.py,sha256=3Mz3V2jf__XU9qNHcH56sBSw95L3U2UPL24bjvobG0c,816
|
531
531
|
omlish/lite/strings.py,sha256=QGxT1Yh4oI8ycsfeobxnjEhvDob_GiAKLeIhZwo1j24,1986
|
532
|
-
omlish/lite/timeouts.py,sha256=
|
532
|
+
omlish/lite/timeouts.py,sha256=NX7gfW4FLYBcewMh4Dg_XlWqJkLY1Fom3z_OLSzuK7M,4969
|
533
533
|
omlish/lite/timing.py,sha256=aVu3hEDB_jyTF_ryZI7iU-xg4q8CNwqpp9Apfru_iwY,196
|
534
534
|
omlish/lite/types.py,sha256=fP5EMyBdEp2LmDxcHjUDtwAMdR06ISr9lKOL7smWfHM,140
|
535
535
|
omlish/lite/typing.py,sha256=U3-JaEnkDSYxK4tsu_MzUn3RP6qALBe5FXQXpD-licE,1090
|
@@ -627,7 +627,7 @@ omlish/os/pidfiles/__main__.py,sha256=AF8TwjK4xgHVnoLAP9dIWgKvT0vGhHJlfDW0tKZ7tx
|
|
627
627
|
omlish/os/pidfiles/cli.py,sha256=2SSsP4O3VdpsDIMAkWgWSjh_YNIPzCD9l5LNN2qrIjo,2074
|
628
628
|
omlish/os/pidfiles/manager.py,sha256=QphQxIENVVwvBWynLCNU31NwOfLkV43VoTVeYFn2Hac,2351
|
629
629
|
omlish/os/pidfiles/pidfile.py,sha256=9tI5IMVwfPfnni0XMn4x5ptNQgm36n8tLeUNPf50UqU,4394
|
630
|
-
omlish/os/pidfiles/pinning.py,sha256=
|
630
|
+
omlish/os/pidfiles/pinning.py,sha256=aQgCmvcAqN0lvI70GcSB2TKVX1G4vwbyN_AOHF3-eKE,6630
|
631
631
|
omlish/reflect/__init__.py,sha256=64eHbD6zL6Fhp7FfXb8n9ZHywlODjBN3rm1LMvZ081A,822
|
632
632
|
omlish/reflect/inspect.py,sha256=WCo2YpBYauKw6k758FLlZ_H4Q05rgVPs96fEv9w6zHQ,1538
|
633
633
|
omlish/reflect/ops.py,sha256=RJ6jzrM4ieFsXzWyNXWV43O_WgzEaUvlHSc5N2ezW2A,2044
|
@@ -649,8 +649,8 @@ omlish/sockets/addresses.py,sha256=vbVeQBkzI513H4vRv-JS89QtRbr9U8v5zqkm3oODl_s,1
|
|
649
649
|
omlish/sockets/bind.py,sha256=J1SfFFFnVf3H5nqESDX2NGEY8DmjyIMUXZciZM33zQY,8003
|
650
650
|
omlish/sockets/handlers.py,sha256=Gj6xZoo4vommge8XvkehYw3B7O4aql2P4qzZIIa0p24,462
|
651
651
|
omlish/sockets/io.py,sha256=lfhTkB7NnAIx9kuQhAkwgsEUXY78Mp1_WtYrIQNS_k8,1408
|
652
|
-
omlish/sockets/ports.py,sha256=
|
653
|
-
omlish/sockets/wait.py,sha256=
|
652
|
+
omlish/sockets/ports.py,sha256=NQYVvd8IBbQkPl8TnBtupTiv-Htqhc6QBIXJJ6GprnQ,1389
|
653
|
+
omlish/sockets/wait.py,sha256=OtLbcoLYzksl4GU0TNbQpzzVWGxp2iRLgo2cGZZfFFM,1559
|
654
654
|
omlish/sockets/server/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
655
655
|
omlish/sockets/server/handlers.py,sha256=PPsb1X5oU9dN8jfztaMGsRiqWTyEANT-1aSLbS6bUVg,3867
|
656
656
|
omlish/sockets/server/server.py,sha256=FkaishIxJuU4it9tTI7wzlGqJYzFGXzDrd_HgV0jAmU,6253
|
@@ -688,10 +688,11 @@ omlish/specs/jmespath/lexer.py,sha256=WGxkwQe_dcHWcJcGg9q6K-8_Q0oRdWkw09dYGFNTHb
|
|
688
688
|
omlish/specs/jmespath/parser.py,sha256=yfkydotVR4LBhrUTsptL_kLYDoGZrRN9zSEs_76kvZM,24441
|
689
689
|
omlish/specs/jmespath/scope.py,sha256=UyDsl9rv_c8DCjJBuVIA2ESu1jrgYvuwEKiaJDQKnT0,1590
|
690
690
|
omlish/specs/jmespath/visitor.py,sha256=HVro_6aBGL0CMBy8NRy6vJzWgwsHGB1qJXldX8H7wSg,16592
|
691
|
-
omlish/specs/jsonrpc/__init__.py,sha256=
|
691
|
+
omlish/specs/jsonrpc/__init__.py,sha256=ugIdqHXWZjSy1R1SkwoxstO2GCHEF4W95Ogl3_5_DV4,544
|
692
|
+
omlish/specs/jsonrpc/conns.py,sha256=zvWnBHuSoGnvbGVk72Usp4IFsLscrzPozqR2hmFjnDI,7029
|
692
693
|
omlish/specs/jsonrpc/errors.py,sha256=-Zgmlo6bV6J8w5f8h9axQgLquIFBHDgIwcpufEH5NsE,707
|
693
694
|
omlish/specs/jsonrpc/marshal.py,sha256=HM736piPGnBZrg8CMLDX-L5fZpegyF6l6JUjzLoSDtk,1852
|
694
|
-
omlish/specs/jsonrpc/types.py,sha256=
|
695
|
+
omlish/specs/jsonrpc/types.py,sha256=Se9ecG-_k-kY_Qlt9QD2t3y26oY4sXTcskp6XZfVans,3054
|
695
696
|
omlish/specs/jsonschema/__init__.py,sha256=55P7Yg2MprqDyaifac2ExNzK6blTZuDP4ejrUXZWpt8,1129
|
696
697
|
omlish/specs/jsonschema/types.py,sha256=_H7ma99hD3_Xu42BFGHOXRI5p79tY8WBX8QE36k7lbw,472
|
697
698
|
omlish/specs/jsonschema/keywords/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -786,11 +787,11 @@ omlish/sql/tabledefs/lower.py,sha256=YQf8gl1kxD5Fm-vOxV6G0Feh_D9PP1pYwz_vz6XjTPQ
|
|
786
787
|
omlish/sql/tabledefs/marshal.py,sha256=x8XG0fJLQ6hlwyu957xqnUhr71ouKiRGBWVueZUEMZU,470
|
787
788
|
omlish/sql/tabledefs/tabledefs.py,sha256=lIhvlt0pk6G7RZAtDFsFXm5j0l9BvRfnP7vNGeydHtE,816
|
788
789
|
omlish/subprocesses/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
789
|
-
omlish/subprocesses/async_.py,sha256=
|
790
|
+
omlish/subprocesses/async_.py,sha256=st7452hRImm6dCwD-Cf293VPeB50xxc8sk_EoRNe_fY,2360
|
790
791
|
omlish/subprocesses/base.py,sha256=W6El-PUKKF9KLAks5LB6kzqs_n3FfkblJ-JOv6NFQbY,6133
|
791
792
|
omlish/subprocesses/editor.py,sha256=tVU1EQsEhCM242HheylQvEsqaAZYnT61kMhlzZcdk5U,2628
|
792
|
-
omlish/subprocesses/run.py,sha256=
|
793
|
-
omlish/subprocesses/sync.py,sha256=
|
793
|
+
omlish/subprocesses/run.py,sha256=ViFvLJYQHAExk0novi8wCx4xk7T4WPH6CTT3P55B6-4,3642
|
794
|
+
omlish/subprocesses/sync.py,sha256=Lmr6LYQrH37wVnlYRQc-fk4iENn2zFGxJmiU8-biUEQ,3658
|
794
795
|
omlish/subprocesses/utils.py,sha256=MJb6hvKhZceTmBeFVqlc5oM7rDxWkUzSzK9nKvbIvM8,396
|
795
796
|
omlish/subprocesses/wrap.py,sha256=HMvCZrO2H227oGNN03KjB3FI-M5bAICqp19W8oG2f5M,763
|
796
797
|
omlish/term/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -852,9 +853,9 @@ omlish/typedvalues/holder.py,sha256=ZTnHiw-K38ciOBLEdwgrltr7Xp8jjEs_0Lp69DH-G-o,
|
|
852
853
|
omlish/typedvalues/marshal.py,sha256=hWHRLcrGav7lvXJDtb9bNI0ickl4SKPQ6F4BbTpqw3A,4219
|
853
854
|
omlish/typedvalues/reflect.py,sha256=Ih1YgU-srUjsvBn_P7C66f73_VCvcwqE3ffeBnZBgt4,674
|
854
855
|
omlish/typedvalues/values.py,sha256=ym46I-q2QJ_6l4UlERqv3yj87R-kp8nCKMRph0xQ3UA,1307
|
855
|
-
omlish-0.0.0.
|
856
|
-
omlish-0.0.0.
|
857
|
-
omlish-0.0.0.
|
858
|
-
omlish-0.0.0.
|
859
|
-
omlish-0.0.0.
|
860
|
-
omlish-0.0.0.
|
856
|
+
omlish-0.0.0.dev309.dist-info/licenses/LICENSE,sha256=B_hVtavaA8zCYDW99DYdcpDLKz1n3BBRjZrcbv8uG8c,1451
|
857
|
+
omlish-0.0.0.dev309.dist-info/METADATA,sha256=whxbYMrVb5r3hPkfUNldkiBM2-N5weht_JZVVwC7rkI,4416
|
858
|
+
omlish-0.0.0.dev309.dist-info/WHEEL,sha256=0CuiUZ_p9E4cD6NyLD6UG80LBXYyiSYZOKDm5lp32xk,91
|
859
|
+
omlish-0.0.0.dev309.dist-info/entry_points.txt,sha256=Lt84WvRZJskWCAS7xnQGZIeVWksprtUHj0llrvVmod8,35
|
860
|
+
omlish-0.0.0.dev309.dist-info/top_level.txt,sha256=pePsKdLu7DvtUiecdYXJ78iO80uDNmBlqe-8hOzOmfs,7
|
861
|
+
omlish-0.0.0.dev309.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|