omlish 0.0.0.dev154__py3-none-any.whl → 0.0.0.dev156__py3-none-any.whl
Sign up to get free protection for your applications and to get access to all the features.
- omlish/__about__.py +2 -2
- omlish/io/fdio/__init__.py +1 -0
- omlish/lite/asyncio/subprocesses.py +132 -161
- omlish/lite/check.py +0 -2
- omlish/lite/contextmanagers.py +14 -0
- omlish/lite/marshal.py +11 -5
- omlish/lite/subprocesses.py +196 -141
- omlish/os/linux.py +484 -0
- omlish/term.py +29 -14
- {omlish-0.0.0.dev154.dist-info → omlish-0.0.0.dev156.dist-info}/METADATA +1 -1
- {omlish-0.0.0.dev154.dist-info → omlish-0.0.0.dev156.dist-info}/RECORD +15 -14
- {omlish-0.0.0.dev154.dist-info → omlish-0.0.0.dev156.dist-info}/LICENSE +0 -0
- {omlish-0.0.0.dev154.dist-info → omlish-0.0.0.dev156.dist-info}/WHEEL +0 -0
- {omlish-0.0.0.dev154.dist-info → omlish-0.0.0.dev156.dist-info}/entry_points.txt +0 -0
- {omlish-0.0.0.dev154.dist-info → omlish-0.0.0.dev156.dist-info}/top_level.txt +0 -0
omlish/__about__.py
CHANGED
omlish/io/fdio/__init__.py
CHANGED
@@ -0,0 +1 @@
|
|
1
|
+
# @omlish-lite
|
@@ -2,8 +2,8 @@
|
|
2
2
|
import asyncio.base_subprocess
|
3
3
|
import asyncio.subprocess
|
4
4
|
import contextlib
|
5
|
+
import dataclasses as dc
|
5
6
|
import functools
|
6
|
-
import logging
|
7
7
|
import subprocess
|
8
8
|
import sys
|
9
9
|
import typing as ta
|
@@ -11,9 +11,7 @@ import typing as ta
|
|
11
11
|
from ...asyncs.asyncio.timeouts import asyncio_maybe_timeout
|
12
12
|
from ..check import check
|
13
13
|
from ..logs import log
|
14
|
-
from ..subprocesses import
|
15
|
-
from ..subprocesses import prepare_subprocess_invocation
|
16
|
-
from ..subprocesses import subprocess_common_context
|
14
|
+
from ..subprocesses import AbstractSubprocesses
|
17
15
|
|
18
16
|
|
19
17
|
T = ta.TypeVar('T')
|
@@ -22,43 +20,6 @@ T = ta.TypeVar('T')
|
|
22
20
|
##
|
23
21
|
|
24
22
|
|
25
|
-
@contextlib.asynccontextmanager
|
26
|
-
async def asyncio_subprocess_popen(
|
27
|
-
*cmd: str,
|
28
|
-
shell: bool = False,
|
29
|
-
timeout: ta.Optional[float] = None,
|
30
|
-
**kwargs: ta.Any,
|
31
|
-
) -> ta.AsyncGenerator[asyncio.subprocess.Process, None]:
|
32
|
-
fac: ta.Any
|
33
|
-
if shell:
|
34
|
-
fac = functools.partial(
|
35
|
-
asyncio.create_subprocess_shell,
|
36
|
-
check.single(cmd),
|
37
|
-
)
|
38
|
-
else:
|
39
|
-
fac = functools.partial(
|
40
|
-
asyncio.create_subprocess_exec,
|
41
|
-
*cmd,
|
42
|
-
)
|
43
|
-
|
44
|
-
with subprocess_common_context(
|
45
|
-
*cmd,
|
46
|
-
shell=shell,
|
47
|
-
timeout=timeout,
|
48
|
-
**kwargs,
|
49
|
-
):
|
50
|
-
proc: asyncio.subprocess.Process
|
51
|
-
proc = await fac(**kwargs)
|
52
|
-
try:
|
53
|
-
yield proc
|
54
|
-
|
55
|
-
finally:
|
56
|
-
await asyncio_maybe_timeout(proc.wait(), timeout)
|
57
|
-
|
58
|
-
|
59
|
-
##
|
60
|
-
|
61
|
-
|
62
23
|
class AsyncioProcessCommunicator:
|
63
24
|
def __init__(
|
64
25
|
self,
|
@@ -169,134 +130,144 @@ class AsyncioProcessCommunicator:
|
|
169
130
|
return await asyncio_maybe_timeout(self._communicate(input), timeout)
|
170
131
|
|
171
132
|
|
172
|
-
|
173
|
-
proc: asyncio.subprocess.Process,
|
174
|
-
input: ta.Any = None, # noqa
|
175
|
-
timeout: ta.Optional[float] = None,
|
176
|
-
) -> ta.Tuple[ta.Optional[bytes], ta.Optional[bytes]]:
|
177
|
-
return await AsyncioProcessCommunicator(proc).communicate(input, timeout) # noqa
|
178
|
-
|
179
|
-
|
180
|
-
async def asyncio_subprocess_run(
|
181
|
-
*args: str,
|
182
|
-
input: ta.Any = None, # noqa
|
183
|
-
timeout: ta.Optional[float] = None,
|
184
|
-
check: bool = False, # noqa
|
185
|
-
capture_output: ta.Optional[bool] = None,
|
186
|
-
**kwargs: ta.Any,
|
187
|
-
) -> ta.Tuple[ta.Optional[bytes], ta.Optional[bytes]]:
|
188
|
-
if capture_output:
|
189
|
-
kwargs.setdefault('stdout', subprocess.PIPE)
|
190
|
-
kwargs.setdefault('stderr', subprocess.PIPE)
|
191
|
-
|
192
|
-
args, kwargs = prepare_subprocess_invocation(*args, **kwargs)
|
193
|
-
|
194
|
-
proc: asyncio.subprocess.Process
|
195
|
-
async with asyncio_subprocess_popen(*args, **kwargs) as proc:
|
196
|
-
stdout, stderr = await asyncio_subprocess_communicate(proc, input, timeout)
|
197
|
-
|
198
|
-
if check and proc.returncode:
|
199
|
-
raise subprocess.CalledProcessError(
|
200
|
-
proc.returncode,
|
201
|
-
args,
|
202
|
-
output=stdout,
|
203
|
-
stderr=stderr,
|
204
|
-
)
|
133
|
+
##
|
205
134
|
|
206
|
-
return stdout, stderr
|
207
135
|
|
136
|
+
class AsyncioSubprocesses(AbstractSubprocesses):
|
137
|
+
async def communicate(
|
138
|
+
self,
|
139
|
+
proc: asyncio.subprocess.Process,
|
140
|
+
input: ta.Any = None, # noqa
|
141
|
+
timeout: ta.Optional[float] = None,
|
142
|
+
) -> ta.Tuple[ta.Optional[bytes], ta.Optional[bytes]]:
|
143
|
+
return await AsyncioProcessCommunicator(proc).communicate(input, timeout) # noqa
|
208
144
|
|
209
|
-
|
145
|
+
#
|
210
146
|
|
147
|
+
@contextlib.asynccontextmanager
|
148
|
+
async def popen(
|
149
|
+
self,
|
150
|
+
*cmd: str,
|
151
|
+
shell: bool = False,
|
152
|
+
timeout: ta.Optional[float] = None,
|
153
|
+
**kwargs: ta.Any,
|
154
|
+
) -> ta.AsyncGenerator[asyncio.subprocess.Process, None]:
|
155
|
+
fac: ta.Any
|
156
|
+
if shell:
|
157
|
+
fac = functools.partial(
|
158
|
+
asyncio.create_subprocess_shell,
|
159
|
+
check.single(cmd),
|
160
|
+
)
|
161
|
+
else:
|
162
|
+
fac = functools.partial(
|
163
|
+
asyncio.create_subprocess_exec,
|
164
|
+
*cmd,
|
165
|
+
)
|
211
166
|
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
timeout: ta.Optional[float] = None,
|
217
|
-
**kwargs: ta.Any,
|
218
|
-
) -> None:
|
219
|
-
_, _ = await asyncio_subprocess_run(
|
220
|
-
*args,
|
221
|
-
stdout=stdout,
|
222
|
-
input=input,
|
223
|
-
timeout=timeout,
|
224
|
-
check=True,
|
225
|
-
**kwargs,
|
226
|
-
)
|
227
|
-
|
228
|
-
|
229
|
-
async def asyncio_subprocess_check_output(
|
230
|
-
*args: str,
|
231
|
-
input: ta.Any = None, # noqa
|
232
|
-
timeout: ta.Optional[float] = None,
|
233
|
-
**kwargs: ta.Any,
|
234
|
-
) -> bytes:
|
235
|
-
stdout, stderr = await asyncio_subprocess_run(
|
236
|
-
*args,
|
237
|
-
stdout=asyncio.subprocess.PIPE,
|
238
|
-
input=input,
|
239
|
-
timeout=timeout,
|
240
|
-
check=True,
|
241
|
-
**kwargs,
|
242
|
-
)
|
243
|
-
|
244
|
-
return check.not_none(stdout)
|
245
|
-
|
246
|
-
|
247
|
-
async def asyncio_subprocess_check_output_str(*args: str, **kwargs: ta.Any) -> str:
|
248
|
-
return (await asyncio_subprocess_check_output(*args, **kwargs)).decode().strip()
|
167
|
+
with self.prepare_and_wrap( *cmd, shell=shell, **kwargs) as (cmd, kwargs): # noqa
|
168
|
+
proc: asyncio.subprocess.Process = await fac(**kwargs)
|
169
|
+
try:
|
170
|
+
yield proc
|
249
171
|
|
172
|
+
finally:
|
173
|
+
await asyncio_maybe_timeout(proc.wait(), timeout)
|
250
174
|
|
251
|
-
|
175
|
+
#
|
252
176
|
|
177
|
+
@dc.dataclass(frozen=True)
|
178
|
+
class RunOutput:
|
179
|
+
proc: asyncio.subprocess.Process
|
180
|
+
stdout: ta.Optional[bytes]
|
181
|
+
stderr: ta.Optional[bytes]
|
253
182
|
|
254
|
-
async def
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
if
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
async
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
return
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
183
|
+
async def run(
|
184
|
+
self,
|
185
|
+
*cmd: str,
|
186
|
+
input: ta.Any = None, # noqa
|
187
|
+
timeout: ta.Optional[float] = None,
|
188
|
+
check: bool = False, # noqa
|
189
|
+
capture_output: ta.Optional[bool] = None,
|
190
|
+
**kwargs: ta.Any,
|
191
|
+
) -> RunOutput:
|
192
|
+
if capture_output:
|
193
|
+
kwargs.setdefault('stdout', subprocess.PIPE)
|
194
|
+
kwargs.setdefault('stderr', subprocess.PIPE)
|
195
|
+
|
196
|
+
proc: asyncio.subprocess.Process
|
197
|
+
async with self.popen(*cmd, **kwargs) as proc:
|
198
|
+
stdout, stderr = await self.communicate(proc, input, timeout)
|
199
|
+
|
200
|
+
if check and proc.returncode:
|
201
|
+
raise subprocess.CalledProcessError(
|
202
|
+
proc.returncode,
|
203
|
+
cmd,
|
204
|
+
output=stdout,
|
205
|
+
stderr=stderr,
|
206
|
+
)
|
207
|
+
|
208
|
+
return self.RunOutput(
|
209
|
+
proc,
|
210
|
+
stdout,
|
211
|
+
stderr,
|
212
|
+
)
|
213
|
+
|
214
|
+
#
|
215
|
+
|
216
|
+
async def check_call(
|
217
|
+
self,
|
218
|
+
*cmd: str,
|
219
|
+
stdout: ta.Any = sys.stderr,
|
220
|
+
**kwargs: ta.Any,
|
221
|
+
) -> None:
|
222
|
+
with self.prepare_and_wrap(*cmd, stdout=stdout, check=True, **kwargs) as (cmd, kwargs): # noqa
|
223
|
+
await self.run(*cmd, **kwargs)
|
224
|
+
|
225
|
+
async def check_output(
|
226
|
+
self,
|
227
|
+
*cmd: str,
|
228
|
+
**kwargs: ta.Any,
|
229
|
+
) -> bytes:
|
230
|
+
with self.prepare_and_wrap(*cmd, stdout=subprocess.PIPE, check=True, **kwargs) as (cmd, kwargs): # noqa
|
231
|
+
return check.not_none((await self.run(*cmd, **kwargs)).stdout)
|
232
|
+
|
233
|
+
async def check_output_str(
|
234
|
+
self,
|
235
|
+
*cmd: str,
|
236
|
+
**kwargs: ta.Any,
|
237
|
+
) -> str:
|
238
|
+
return (await self.check_output(*cmd, **kwargs)).decode().strip()
|
239
|
+
|
240
|
+
#
|
241
|
+
|
242
|
+
async def try_call(
|
243
|
+
self,
|
244
|
+
*cmd: str,
|
245
|
+
**kwargs: ta.Any,
|
246
|
+
) -> bool:
|
247
|
+
if isinstance(await self.async_try_fn(self.check_call, *cmd, **kwargs), Exception):
|
248
|
+
return False
|
249
|
+
else:
|
250
|
+
return True
|
251
|
+
|
252
|
+
async def try_output(
|
253
|
+
self,
|
254
|
+
*cmd: str,
|
255
|
+
**kwargs: ta.Any,
|
256
|
+
) -> ta.Optional[bytes]:
|
257
|
+
if isinstance(ret := await self.async_try_fn(self.check_output, *cmd, **kwargs), Exception):
|
258
|
+
return None
|
259
|
+
else:
|
260
|
+
return ret
|
261
|
+
|
262
|
+
async def try_output_str(
|
263
|
+
self,
|
264
|
+
*cmd: str,
|
265
|
+
**kwargs: ta.Any,
|
266
|
+
) -> ta.Optional[str]:
|
267
|
+
if (ret := await self.try_output(*cmd, **kwargs)) is None:
|
268
|
+
return None
|
269
|
+
else:
|
270
|
+
return ret.decode().strip()
|
298
271
|
|
299
272
|
|
300
|
-
|
301
|
-
out = await asyncio_subprocess_try_output(*args, **kwargs)
|
302
|
-
return out.decode().strip() if out is not None else None
|
273
|
+
asyncio_subprocesses = AsyncioSubprocesses()
|
omlish/lite/check.py
CHANGED
omlish/lite/contextmanagers.py
CHANGED
@@ -61,3 +61,17 @@ def attr_setting(obj, attr, val, *, default=None): # noqa
|
|
61
61
|
delattr(obj, attr)
|
62
62
|
else:
|
63
63
|
setattr(obj, attr, orig)
|
64
|
+
|
65
|
+
|
66
|
+
##
|
67
|
+
|
68
|
+
|
69
|
+
class aclosing(contextlib.AbstractAsyncContextManager): # noqa
|
70
|
+
def __init__(self, thing):
|
71
|
+
self.thing = thing
|
72
|
+
|
73
|
+
async def __aenter__(self):
|
74
|
+
return self.thing
|
75
|
+
|
76
|
+
async def __aexit__(self, *exc_info):
|
77
|
+
await self.thing.aclose()
|
omlish/lite/marshal.py
CHANGED
@@ -1,7 +1,8 @@
|
|
1
1
|
"""
|
2
2
|
TODO:
|
3
3
|
- pickle stdlib objs? have to pin to 3.8 pickle protocol, will be cross-version
|
4
|
-
-
|
4
|
+
- namedtuple
|
5
|
+
- literals
|
5
6
|
"""
|
6
7
|
# ruff: noqa: UP006 UP007
|
7
8
|
import abc
|
@@ -23,6 +24,7 @@ from .reflect import deep_subclasses
|
|
23
24
|
from .reflect import get_optional_alias_arg
|
24
25
|
from .reflect import is_generic_alias
|
25
26
|
from .reflect import is_union_alias
|
27
|
+
from .strings import snake_case
|
26
28
|
|
27
29
|
|
28
30
|
T = ta.TypeVar('T')
|
@@ -314,14 +316,18 @@ class ObjMarshalerManager:
|
|
314
316
|
) -> ObjMarshaler:
|
315
317
|
if isinstance(ty, type):
|
316
318
|
if abc.ABC in ty.__bases__:
|
317
|
-
|
319
|
+
impls = [ity for ity in deep_subclasses(ty) if abc.ABC not in ity.__bases__] # type: ignore
|
320
|
+
if all(ity.__qualname__.endswith(ty.__name__) for ity in impls):
|
321
|
+
ins = {ity: snake_case(ity.__qualname__[:-len(ty.__name__)]) for ity in impls}
|
322
|
+
else:
|
323
|
+
ins = {ity: ity.__qualname__ for ity in impls}
|
324
|
+
return PolymorphicObjMarshaler.of([
|
318
325
|
PolymorphicObjMarshaler.Impl(
|
319
326
|
ity,
|
320
|
-
|
327
|
+
itn,
|
321
328
|
rec(ity),
|
322
329
|
)
|
323
|
-
for ity in
|
324
|
-
if abc.ABC not in ity.__bases__
|
330
|
+
for ity, itn in ins.items()
|
325
331
|
])
|
326
332
|
|
327
333
|
if issubclass(ty, enum.Enum):
|