omlish 0.0.0.dev154__py3-none-any.whl → 0.0.0.dev156__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/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):
|