omlish 0.0.0.dev133__py3-none-any.whl → 0.0.0.dev177__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/.manifests.json +265 -7
- omlish/__about__.py +5 -3
- omlish/antlr/_runtime/__init__.py +0 -22
- omlish/antlr/_runtime/_all.py +24 -0
- omlish/antlr/_runtime/atn/ParserATNSimulator.py +1 -1
- omlish/antlr/_runtime/dfa/DFASerializer.py +1 -1
- omlish/antlr/_runtime/error/DiagnosticErrorListener.py +2 -1
- omlish/antlr/_runtime/xpath/XPath.py +7 -1
- omlish/antlr/_runtime/xpath/XPathLexer.py +1 -1
- omlish/antlr/delimit.py +106 -0
- omlish/antlr/dot.py +31 -0
- omlish/antlr/errors.py +11 -0
- omlish/antlr/input.py +96 -0
- omlish/antlr/parsing.py +19 -0
- omlish/antlr/runtime.py +102 -0
- omlish/antlr/utils.py +38 -0
- omlish/argparse/all.py +45 -0
- omlish/{argparse.py → argparse/cli.py} +112 -107
- omlish/asyncs/__init__.py +0 -35
- omlish/asyncs/all.py +35 -0
- omlish/asyncs/asyncio/all.py +7 -0
- omlish/asyncs/asyncio/channels.py +40 -0
- omlish/asyncs/asyncio/streams.py +45 -0
- omlish/asyncs/asyncio/subprocesses.py +238 -0
- omlish/asyncs/asyncio/timeouts.py +16 -0
- omlish/asyncs/bluelet/LICENSE +6 -0
- omlish/asyncs/bluelet/all.py +67 -0
- omlish/asyncs/bluelet/api.py +23 -0
- omlish/asyncs/bluelet/core.py +178 -0
- omlish/asyncs/bluelet/events.py +78 -0
- omlish/asyncs/bluelet/files.py +80 -0
- omlish/asyncs/bluelet/runner.py +416 -0
- omlish/asyncs/bluelet/sockets.py +214 -0
- omlish/bootstrap/sys.py +3 -3
- omlish/cached.py +2 -2
- omlish/check.py +49 -460
- omlish/codecs/__init__.py +72 -0
- omlish/codecs/base.py +106 -0
- omlish/codecs/bytes.py +119 -0
- omlish/codecs/chain.py +23 -0
- omlish/codecs/funcs.py +39 -0
- omlish/codecs/registry.py +139 -0
- omlish/codecs/standard.py +4 -0
- omlish/codecs/text.py +217 -0
- omlish/collections/cache/impl.py +50 -57
- omlish/collections/coerce.py +1 -0
- omlish/collections/mappings.py +1 -1
- omlish/configs/flattening.py +1 -1
- omlish/defs.py +1 -1
- omlish/diag/_pycharm/runhack.py +8 -2
- omlish/diag/procfs.py +8 -8
- omlish/docker/__init__.py +0 -36
- omlish/docker/all.py +31 -0
- omlish/docker/consts.py +4 -0
- omlish/{lite/docker.py → docker/detect.py} +18 -0
- omlish/docker/{helpers.py → timebomb.py} +0 -21
- omlish/formats/cbor.py +31 -0
- omlish/formats/cloudpickle.py +31 -0
- omlish/formats/codecs.py +93 -0
- omlish/formats/json/codecs.py +29 -0
- omlish/formats/json/delimted.py +4 -0
- omlish/formats/json/stream/errors.py +2 -0
- omlish/formats/json/stream/lex.py +12 -6
- omlish/formats/json/stream/parse.py +38 -22
- omlish/formats/json5.py +31 -0
- omlish/formats/pickle.py +31 -0
- omlish/formats/repr.py +25 -0
- omlish/formats/toml.py +17 -0
- omlish/formats/yaml.py +25 -0
- omlish/funcs/__init__.py +0 -0
- omlish/{genmachine.py → funcs/genmachine.py} +5 -4
- omlish/{matchfns.py → funcs/match.py} +1 -1
- omlish/funcs/pairs.py +215 -0
- omlish/http/__init__.py +0 -48
- omlish/http/all.py +48 -0
- omlish/http/coro/__init__.py +0 -0
- omlish/{lite/fdio/corohttp.py → http/coro/fdio.py} +21 -19
- omlish/{lite/http/coroserver.py → http/coro/server.py} +20 -21
- omlish/{lite/http → http}/handlers.py +3 -2
- omlish/{lite/http → http}/parsing.py +1 -0
- omlish/http/sessions.py +1 -1
- omlish/{lite/http → http}/versions.py +1 -0
- omlish/inject/managed.py +2 -2
- omlish/io/__init__.py +0 -3
- omlish/{lite/io.py → io/buffers.py} +8 -9
- omlish/io/compress/__init__.py +9 -0
- omlish/io/compress/abc.py +104 -0
- omlish/io/compress/adapters.py +148 -0
- omlish/io/compress/base.py +24 -0
- omlish/io/compress/brotli.py +47 -0
- omlish/io/compress/bz2.py +61 -0
- omlish/io/compress/codecs.py +78 -0
- omlish/io/compress/gzip.py +350 -0
- omlish/io/compress/lz4.py +91 -0
- omlish/io/compress/lzma.py +81 -0
- omlish/io/compress/snappy.py +34 -0
- omlish/io/compress/zlib.py +74 -0
- omlish/io/compress/zstd.py +44 -0
- omlish/io/fdio/__init__.py +1 -0
- omlish/{lite → io}/fdio/handlers.py +5 -5
- omlish/{lite → io}/fdio/kqueue.py +8 -8
- omlish/{lite → io}/fdio/manager.py +7 -7
- omlish/{lite → io}/fdio/pollers.py +13 -13
- omlish/io/generators/__init__.py +56 -0
- omlish/io/generators/consts.py +1 -0
- omlish/io/generators/direct.py +13 -0
- omlish/io/generators/readers.py +189 -0
- omlish/io/generators/stepped.py +191 -0
- omlish/io/pyio.py +5 -2
- omlish/iterators/__init__.py +24 -0
- omlish/iterators/iterators.py +132 -0
- omlish/iterators/recipes.py +18 -0
- omlish/iterators/tools.py +96 -0
- omlish/iterators/unique.py +67 -0
- omlish/lang/__init__.py +13 -1
- omlish/lang/functions.py +11 -2
- omlish/lang/generators.py +243 -0
- omlish/lang/iterables.py +46 -49
- omlish/lang/maybes.py +4 -4
- omlish/lite/cached.py +39 -6
- omlish/lite/check.py +438 -75
- omlish/lite/contextmanagers.py +17 -4
- omlish/lite/dataclasses.py +42 -0
- omlish/lite/inject.py +28 -45
- omlish/lite/logs.py +0 -270
- omlish/lite/marshal.py +309 -144
- omlish/lite/pycharm.py +47 -0
- omlish/lite/reflect.py +33 -0
- omlish/lite/resources.py +8 -0
- omlish/lite/runtime.py +4 -4
- omlish/lite/shlex.py +12 -0
- omlish/lite/socketserver.py +2 -2
- omlish/lite/strings.py +31 -0
- omlish/logs/__init__.py +0 -32
- omlish/logs/{_abc.py → abc.py} +0 -1
- omlish/logs/all.py +37 -0
- omlish/logs/{formatters.py → color.py} +1 -2
- omlish/logs/configs.py +7 -38
- omlish/logs/filters.py +10 -0
- omlish/logs/handlers.py +4 -1
- omlish/logs/json.py +56 -0
- omlish/logs/proxy.py +99 -0
- omlish/logs/standard.py +128 -0
- omlish/logs/utils.py +2 -2
- omlish/manifests/__init__.py +2 -0
- omlish/manifests/load.py +209 -0
- omlish/manifests/types.py +17 -0
- omlish/marshal/base.py +1 -1
- omlish/marshal/factories.py +1 -1
- omlish/marshal/forbidden.py +1 -1
- omlish/marshal/iterables.py +1 -1
- omlish/marshal/literals.py +50 -0
- omlish/marshal/mappings.py +1 -1
- omlish/marshal/maybes.py +1 -1
- omlish/marshal/standard.py +5 -1
- omlish/marshal/unions.py +1 -1
- omlish/os/__init__.py +0 -0
- omlish/os/atomics.py +205 -0
- omlish/os/deathsig.py +23 -0
- omlish/{os.py → os/files.py} +0 -9
- omlish/{lite → os}/journald.py +2 -1
- omlish/os/linux.py +484 -0
- omlish/os/paths.py +36 -0
- omlish/{lite → os}/pidfile.py +1 -0
- omlish/os/sizes.py +9 -0
- omlish/reflect/__init__.py +3 -0
- omlish/reflect/subst.py +2 -1
- omlish/reflect/types.py +126 -44
- omlish/secrets/pwhash.py +1 -1
- omlish/secrets/subprocesses.py +3 -1
- omlish/specs/jsonrpc/marshal.py +1 -1
- omlish/specs/openapi/marshal.py +1 -1
- omlish/sql/alchemy/asyncs.py +1 -1
- omlish/sql/queries/__init__.py +9 -1
- omlish/sql/queries/building.py +3 -0
- omlish/sql/queries/exprs.py +10 -27
- omlish/sql/queries/idents.py +48 -10
- omlish/sql/queries/names.py +80 -13
- omlish/sql/queries/params.py +64 -0
- omlish/sql/queries/rendering.py +1 -1
- omlish/subprocesses.py +340 -0
- omlish/term.py +29 -14
- omlish/testing/pytest/marks.py +2 -2
- omlish/testing/pytest/plugins/asyncs.py +6 -1
- omlish/testing/pytest/plugins/logging.py +1 -1
- omlish/testing/pytest/plugins/switches.py +1 -1
- {omlish-0.0.0.dev133.dist-info → omlish-0.0.0.dev177.dist-info}/METADATA +7 -5
- {omlish-0.0.0.dev133.dist-info → omlish-0.0.0.dev177.dist-info}/RECORD +200 -117
- omlish/fnpairs.py +0 -496
- omlish/formats/json/cli/__main__.py +0 -11
- omlish/formats/json/cli/cli.py +0 -298
- omlish/formats/json/cli/formats.py +0 -71
- omlish/formats/json/cli/io.py +0 -74
- omlish/formats/json/cli/parsing.py +0 -82
- omlish/formats/json/cli/processing.py +0 -48
- omlish/formats/json/cli/rendering.py +0 -92
- omlish/iterators.py +0 -300
- omlish/lite/subprocesses.py +0 -130
- /omlish/{formats/json/cli → argparse}/__init__.py +0 -0
- /omlish/{lite/fdio → asyncs/asyncio}/__init__.py +0 -0
- /omlish/asyncs/{asyncio.py → asyncio/asyncio.py} +0 -0
- /omlish/{lite/http → asyncs/bluelet}/__init__.py +0 -0
- /omlish/collections/{_abc.py → abc.py} +0 -0
- /omlish/{fnpipes.py → funcs/pipes.py} +0 -0
- /omlish/io/{_abc.py → abc.py} +0 -0
- /omlish/sql/{_abc.py → abc.py} +0 -0
- {omlish-0.0.0.dev133.dist-info → omlish-0.0.0.dev177.dist-info}/LICENSE +0 -0
- {omlish-0.0.0.dev133.dist-info → omlish-0.0.0.dev177.dist-info}/WHEEL +0 -0
- {omlish-0.0.0.dev133.dist-info → omlish-0.0.0.dev177.dist-info}/entry_points.txt +0 -0
- {omlish-0.0.0.dev133.dist-info → omlish-0.0.0.dev177.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,64 @@
|
|
1
|
+
import typing as ta
|
2
|
+
|
3
|
+
from ... import lang
|
4
|
+
from .base import Builder
|
5
|
+
from .exprs import Expr
|
6
|
+
|
7
|
+
|
8
|
+
##
|
9
|
+
|
10
|
+
|
11
|
+
class Param(Expr, lang.Final):
|
12
|
+
n: str | None = None
|
13
|
+
|
14
|
+
def __repr__(self) -> str:
|
15
|
+
if self.n is not None:
|
16
|
+
return f'{self.__class__.__name__}({self.n!r})'
|
17
|
+
else:
|
18
|
+
return f'{self.__class__.__name__}(@{hex(id(self))[2:]})'
|
19
|
+
|
20
|
+
def __eq__(self, other):
|
21
|
+
if not isinstance(other, Param):
|
22
|
+
return False
|
23
|
+
if self.n is None and other.n is None:
|
24
|
+
return self is other
|
25
|
+
else:
|
26
|
+
return self.n == other.n
|
27
|
+
|
28
|
+
|
29
|
+
##
|
30
|
+
|
31
|
+
|
32
|
+
CanParam: ta.TypeAlias = Param | str | None
|
33
|
+
|
34
|
+
|
35
|
+
def as_param(o: CanParam = None) -> Param:
|
36
|
+
if isinstance(o, Param):
|
37
|
+
return o
|
38
|
+
else:
|
39
|
+
return Param(o)
|
40
|
+
|
41
|
+
|
42
|
+
##
|
43
|
+
|
44
|
+
|
45
|
+
class ParamAccessor(lang.Final):
|
46
|
+
def __getattr__(self, s: str) -> Param:
|
47
|
+
return Param(s)
|
48
|
+
|
49
|
+
def __call__(self, o: CanParam = None) -> Param:
|
50
|
+
return as_param(o)
|
51
|
+
|
52
|
+
|
53
|
+
##
|
54
|
+
|
55
|
+
|
56
|
+
class ParamBuilder(Builder):
|
57
|
+
@ta.final
|
58
|
+
def param(self, o: CanParam = None) -> Param:
|
59
|
+
return as_param(o)
|
60
|
+
|
61
|
+
@ta.final
|
62
|
+
@property
|
63
|
+
def p(self) -> ParamAccessor:
|
64
|
+
return ParamAccessor()
|
omlish/sql/queries/rendering.py
CHANGED
@@ -29,13 +29,13 @@ from .binary import BinaryOp
|
|
29
29
|
from .binary import BinaryOps
|
30
30
|
from .exprs import Literal
|
31
31
|
from .exprs import NameExpr
|
32
|
-
from .exprs import Param
|
33
32
|
from .idents import Ident
|
34
33
|
from .inserts import Insert
|
35
34
|
from .inserts import Values
|
36
35
|
from .multi import Multi
|
37
36
|
from .multi import MultiKind
|
38
37
|
from .names import Name
|
38
|
+
from .params import Param
|
39
39
|
from .relations import Table
|
40
40
|
from .selects import Select
|
41
41
|
from .selects import SelectItem
|
omlish/subprocesses.py
ADDED
@@ -0,0 +1,340 @@
|
|
1
|
+
# ruff: noqa: UP006 UP007
|
2
|
+
import abc
|
3
|
+
import contextlib
|
4
|
+
import logging
|
5
|
+
import os
|
6
|
+
import shlex
|
7
|
+
import subprocess
|
8
|
+
import sys
|
9
|
+
import time
|
10
|
+
import typing as ta
|
11
|
+
|
12
|
+
from .lite.runtime import is_debugger_attached
|
13
|
+
|
14
|
+
|
15
|
+
T = ta.TypeVar('T')
|
16
|
+
SubprocessChannelOption = ta.Literal['pipe', 'stdout', 'devnull'] # ta.TypeAlias
|
17
|
+
|
18
|
+
|
19
|
+
##
|
20
|
+
|
21
|
+
|
22
|
+
SUBPROCESS_CHANNEL_OPTION_VALUES: ta.Mapping[SubprocessChannelOption, int] = {
|
23
|
+
'pipe': subprocess.PIPE,
|
24
|
+
'stdout': subprocess.STDOUT,
|
25
|
+
'devnull': subprocess.DEVNULL,
|
26
|
+
}
|
27
|
+
|
28
|
+
|
29
|
+
##
|
30
|
+
|
31
|
+
|
32
|
+
_SUBPROCESS_SHELL_WRAP_EXECS = False
|
33
|
+
|
34
|
+
|
35
|
+
def subprocess_shell_wrap_exec(*cmd: str) -> ta.Tuple[str, ...]:
|
36
|
+
return ('sh', '-c', ' '.join(map(shlex.quote, cmd)))
|
37
|
+
|
38
|
+
|
39
|
+
def subprocess_maybe_shell_wrap_exec(*cmd: str) -> ta.Tuple[str, ...]:
|
40
|
+
if _SUBPROCESS_SHELL_WRAP_EXECS or is_debugger_attached():
|
41
|
+
return subprocess_shell_wrap_exec(*cmd)
|
42
|
+
else:
|
43
|
+
return cmd
|
44
|
+
|
45
|
+
|
46
|
+
##
|
47
|
+
|
48
|
+
|
49
|
+
def subprocess_close(
|
50
|
+
proc: subprocess.Popen,
|
51
|
+
timeout: ta.Optional[float] = None,
|
52
|
+
) -> None:
|
53
|
+
# TODO: terminate, sleep, kill
|
54
|
+
if proc.stdout:
|
55
|
+
proc.stdout.close()
|
56
|
+
if proc.stderr:
|
57
|
+
proc.stderr.close()
|
58
|
+
if proc.stdin:
|
59
|
+
proc.stdin.close()
|
60
|
+
|
61
|
+
proc.wait(timeout)
|
62
|
+
|
63
|
+
|
64
|
+
##
|
65
|
+
|
66
|
+
|
67
|
+
class BaseSubprocesses(abc.ABC): # noqa
|
68
|
+
DEFAULT_LOGGER: ta.ClassVar[ta.Optional[logging.Logger]] = None
|
69
|
+
|
70
|
+
def __init__(
|
71
|
+
self,
|
72
|
+
*,
|
73
|
+
log: ta.Optional[logging.Logger] = None,
|
74
|
+
try_exceptions: ta.Optional[ta.Tuple[ta.Type[Exception], ...]] = None,
|
75
|
+
) -> None:
|
76
|
+
super().__init__()
|
77
|
+
|
78
|
+
self._log = log if log is not None else self.DEFAULT_LOGGER
|
79
|
+
self._try_exceptions = try_exceptions if try_exceptions is not None else self.DEFAULT_TRY_EXCEPTIONS
|
80
|
+
|
81
|
+
def set_logger(self, log: ta.Optional[logging.Logger]) -> None:
|
82
|
+
self._log = log
|
83
|
+
|
84
|
+
#
|
85
|
+
|
86
|
+
def prepare_args(
|
87
|
+
self,
|
88
|
+
*cmd: str,
|
89
|
+
env: ta.Optional[ta.Mapping[str, ta.Any]] = None,
|
90
|
+
extra_env: ta.Optional[ta.Mapping[str, ta.Any]] = None,
|
91
|
+
quiet: bool = False,
|
92
|
+
shell: bool = False,
|
93
|
+
**kwargs: ta.Any,
|
94
|
+
) -> ta.Tuple[ta.Tuple[ta.Any, ...], ta.Dict[str, ta.Any]]:
|
95
|
+
if self._log:
|
96
|
+
self._log.debug('Subprocesses.prepare_args: cmd=%r', cmd)
|
97
|
+
if extra_env:
|
98
|
+
self._log.debug('Subprocesses.prepare_args: extra_env=%r', extra_env)
|
99
|
+
|
100
|
+
if extra_env:
|
101
|
+
env = {**(env if env is not None else os.environ), **extra_env}
|
102
|
+
|
103
|
+
if quiet and 'stderr' not in kwargs:
|
104
|
+
if self._log and not self._log.isEnabledFor(logging.DEBUG):
|
105
|
+
kwargs['stderr'] = subprocess.DEVNULL
|
106
|
+
|
107
|
+
if not shell:
|
108
|
+
cmd = subprocess_maybe_shell_wrap_exec(*cmd)
|
109
|
+
|
110
|
+
return cmd, dict(
|
111
|
+
env=env,
|
112
|
+
shell=shell,
|
113
|
+
**kwargs,
|
114
|
+
)
|
115
|
+
|
116
|
+
@contextlib.contextmanager
|
117
|
+
def wrap_call(self, *cmd: ta.Any, **kwargs: ta.Any) -> ta.Iterator[None]:
|
118
|
+
start_time = time.time()
|
119
|
+
try:
|
120
|
+
if self._log:
|
121
|
+
self._log.debug('Subprocesses.wrap_call.try: cmd=%r', cmd)
|
122
|
+
yield
|
123
|
+
|
124
|
+
except Exception as exc: # noqa
|
125
|
+
if self._log:
|
126
|
+
self._log.debug('Subprocesses.wrap_call.except: exc=%r', exc)
|
127
|
+
raise
|
128
|
+
|
129
|
+
finally:
|
130
|
+
end_time = time.time()
|
131
|
+
elapsed_s = end_time - start_time
|
132
|
+
if self._log:
|
133
|
+
self._log.debug('sSubprocesses.wrap_call.finally: elapsed_s=%f cmd=%r', elapsed_s, cmd)
|
134
|
+
|
135
|
+
@contextlib.contextmanager
|
136
|
+
def prepare_and_wrap(
|
137
|
+
self,
|
138
|
+
*cmd: ta.Any,
|
139
|
+
**kwargs: ta.Any,
|
140
|
+
) -> ta.Iterator[ta.Tuple[
|
141
|
+
ta.Tuple[ta.Any, ...],
|
142
|
+
ta.Dict[str, ta.Any],
|
143
|
+
]]:
|
144
|
+
cmd, kwargs = self.prepare_args(*cmd, **kwargs)
|
145
|
+
with self.wrap_call(*cmd, **kwargs):
|
146
|
+
yield cmd, kwargs
|
147
|
+
|
148
|
+
#
|
149
|
+
|
150
|
+
DEFAULT_TRY_EXCEPTIONS: ta.Tuple[ta.Type[Exception], ...] = (
|
151
|
+
FileNotFoundError,
|
152
|
+
subprocess.CalledProcessError,
|
153
|
+
)
|
154
|
+
|
155
|
+
def try_fn(
|
156
|
+
self,
|
157
|
+
fn: ta.Callable[..., T],
|
158
|
+
*cmd: str,
|
159
|
+
try_exceptions: ta.Optional[ta.Tuple[ta.Type[Exception], ...]] = None,
|
160
|
+
**kwargs: ta.Any,
|
161
|
+
) -> ta.Union[T, Exception]:
|
162
|
+
if try_exceptions is None:
|
163
|
+
try_exceptions = self._try_exceptions
|
164
|
+
|
165
|
+
try:
|
166
|
+
return fn(*cmd, **kwargs)
|
167
|
+
|
168
|
+
except try_exceptions as e: # noqa
|
169
|
+
if self._log and self._log.isEnabledFor(logging.DEBUG):
|
170
|
+
self._log.exception('command failed')
|
171
|
+
return e
|
172
|
+
|
173
|
+
async def async_try_fn(
|
174
|
+
self,
|
175
|
+
fn: ta.Callable[..., ta.Awaitable[T]],
|
176
|
+
*cmd: ta.Any,
|
177
|
+
try_exceptions: ta.Optional[ta.Tuple[ta.Type[Exception], ...]] = None,
|
178
|
+
**kwargs: ta.Any,
|
179
|
+
) -> ta.Union[T, Exception]:
|
180
|
+
if try_exceptions is None:
|
181
|
+
try_exceptions = self._try_exceptions
|
182
|
+
|
183
|
+
try:
|
184
|
+
return await fn(*cmd, **kwargs)
|
185
|
+
|
186
|
+
except try_exceptions as e: # noqa
|
187
|
+
if self._log and self._log.isEnabledFor(logging.DEBUG):
|
188
|
+
self._log.exception('command failed')
|
189
|
+
return e
|
190
|
+
|
191
|
+
|
192
|
+
##
|
193
|
+
|
194
|
+
|
195
|
+
class AbstractSubprocesses(BaseSubprocesses, abc.ABC):
|
196
|
+
@abc.abstractmethod
|
197
|
+
def check_call(
|
198
|
+
self,
|
199
|
+
*cmd: str,
|
200
|
+
stdout: ta.Any = sys.stderr,
|
201
|
+
**kwargs: ta.Any,
|
202
|
+
) -> None:
|
203
|
+
raise NotImplementedError
|
204
|
+
|
205
|
+
@abc.abstractmethod
|
206
|
+
def check_output(
|
207
|
+
self,
|
208
|
+
*cmd: str,
|
209
|
+
**kwargs: ta.Any,
|
210
|
+
) -> bytes:
|
211
|
+
raise NotImplementedError
|
212
|
+
|
213
|
+
#
|
214
|
+
|
215
|
+
def check_output_str(
|
216
|
+
self,
|
217
|
+
*cmd: str,
|
218
|
+
**kwargs: ta.Any,
|
219
|
+
) -> str:
|
220
|
+
return self.check_output(*cmd, **kwargs).decode().strip()
|
221
|
+
|
222
|
+
#
|
223
|
+
|
224
|
+
def try_call(
|
225
|
+
self,
|
226
|
+
*cmd: str,
|
227
|
+
**kwargs: ta.Any,
|
228
|
+
) -> bool:
|
229
|
+
if isinstance(self.try_fn(self.check_call, *cmd, **kwargs), Exception):
|
230
|
+
return False
|
231
|
+
else:
|
232
|
+
return True
|
233
|
+
|
234
|
+
def try_output(
|
235
|
+
self,
|
236
|
+
*cmd: str,
|
237
|
+
**kwargs: ta.Any,
|
238
|
+
) -> ta.Optional[bytes]:
|
239
|
+
if isinstance(ret := self.try_fn(self.check_output, *cmd, **kwargs), Exception):
|
240
|
+
return None
|
241
|
+
else:
|
242
|
+
return ret
|
243
|
+
|
244
|
+
def try_output_str(
|
245
|
+
self,
|
246
|
+
*cmd: str,
|
247
|
+
**kwargs: ta.Any,
|
248
|
+
) -> ta.Optional[str]:
|
249
|
+
if (ret := self.try_output(*cmd, **kwargs)) is None:
|
250
|
+
return None
|
251
|
+
else:
|
252
|
+
return ret.decode().strip()
|
253
|
+
|
254
|
+
|
255
|
+
##
|
256
|
+
|
257
|
+
|
258
|
+
class Subprocesses(AbstractSubprocesses):
|
259
|
+
def check_call(
|
260
|
+
self,
|
261
|
+
*cmd: str,
|
262
|
+
stdout: ta.Any = sys.stderr,
|
263
|
+
**kwargs: ta.Any,
|
264
|
+
) -> None:
|
265
|
+
with self.prepare_and_wrap(*cmd, stdout=stdout, **kwargs) as (cmd, kwargs): # noqa
|
266
|
+
subprocess.check_call(cmd, **kwargs)
|
267
|
+
|
268
|
+
def check_output(
|
269
|
+
self,
|
270
|
+
*cmd: str,
|
271
|
+
**kwargs: ta.Any,
|
272
|
+
) -> bytes:
|
273
|
+
with self.prepare_and_wrap(*cmd, **kwargs) as (cmd, kwargs): # noqa
|
274
|
+
return subprocess.check_output(cmd, **kwargs)
|
275
|
+
|
276
|
+
|
277
|
+
subprocesses = Subprocesses()
|
278
|
+
|
279
|
+
|
280
|
+
##
|
281
|
+
|
282
|
+
|
283
|
+
class AbstractAsyncSubprocesses(BaseSubprocesses):
|
284
|
+
@abc.abstractmethod
|
285
|
+
async def check_call(
|
286
|
+
self,
|
287
|
+
*cmd: str,
|
288
|
+
stdout: ta.Any = sys.stderr,
|
289
|
+
**kwargs: ta.Any,
|
290
|
+
) -> None:
|
291
|
+
raise NotImplementedError
|
292
|
+
|
293
|
+
@abc.abstractmethod
|
294
|
+
async def check_output(
|
295
|
+
self,
|
296
|
+
*cmd: str,
|
297
|
+
**kwargs: ta.Any,
|
298
|
+
) -> bytes:
|
299
|
+
raise NotImplementedError
|
300
|
+
|
301
|
+
#
|
302
|
+
|
303
|
+
async def check_output_str(
|
304
|
+
self,
|
305
|
+
*cmd: str,
|
306
|
+
**kwargs: ta.Any,
|
307
|
+
) -> str:
|
308
|
+
return (await self.check_output(*cmd, **kwargs)).decode().strip()
|
309
|
+
|
310
|
+
#
|
311
|
+
|
312
|
+
async def try_call(
|
313
|
+
self,
|
314
|
+
*cmd: str,
|
315
|
+
**kwargs: ta.Any,
|
316
|
+
) -> bool:
|
317
|
+
if isinstance(await self.async_try_fn(self.check_call, *cmd, **kwargs), Exception):
|
318
|
+
return False
|
319
|
+
else:
|
320
|
+
return True
|
321
|
+
|
322
|
+
async def try_output(
|
323
|
+
self,
|
324
|
+
*cmd: str,
|
325
|
+
**kwargs: ta.Any,
|
326
|
+
) -> ta.Optional[bytes]:
|
327
|
+
if isinstance(ret := await self.async_try_fn(self.check_output, *cmd, **kwargs), Exception):
|
328
|
+
return None
|
329
|
+
else:
|
330
|
+
return ret
|
331
|
+
|
332
|
+
async def try_output_str(
|
333
|
+
self,
|
334
|
+
*cmd: str,
|
335
|
+
**kwargs: ta.Any,
|
336
|
+
) -> ta.Optional[str]:
|
337
|
+
if (ret := await self.try_output(*cmd, **kwargs)) is None:
|
338
|
+
return None
|
339
|
+
else:
|
340
|
+
return ret.decode().strip()
|
omlish/term.py
CHANGED
@@ -172,48 +172,63 @@ def _clamp_ofs(v: int, hi: int, ofs: int) -> str:
|
|
172
172
|
|
173
173
|
FG8 = ControlSequence(
|
174
174
|
lambda n: CSI + '38;5;' + str(n) + 'm',
|
175
|
-
'8-Bit Foreground Color'
|
175
|
+
'8-Bit Foreground Color',
|
176
|
+
)
|
176
177
|
FG8_STANDARD = ControlSequence(
|
177
178
|
lambda n: CSI + '38;5;' + _clamp_ofs(n, 8, 0) + 'm',
|
178
|
-
'8-Bit Foreground Color (Standard)'
|
179
|
+
'8-Bit Foreground Color (Standard)',
|
180
|
+
)
|
179
181
|
FG8_HIGH_INTENSITY = ControlSequence(
|
180
182
|
lambda n: CSI + '38;5;' + _clamp_ofs(n, 8, 8) + 'm',
|
181
|
-
'8-Bit Foreground Color (High Intensity)'
|
183
|
+
'8-Bit Foreground Color (High Intensity)',
|
184
|
+
)
|
182
185
|
FG8_216 = ControlSequence(
|
183
186
|
lambda n: CSI + '38;5;' + _clamp_ofs(n, 216, 16) + 'm',
|
184
|
-
'8-Bit Foreground Color (High Intensity)'
|
187
|
+
'8-Bit Foreground Color (High Intensity)',
|
188
|
+
)
|
185
189
|
FG8_GRAYSCALE = ControlSequence(
|
186
190
|
lambda n: CSI + '38;5;' + _clamp_ofs(n, 24, 232) + 'm',
|
187
|
-
'8-Bit Foreground Color (Grayscale)'
|
191
|
+
'8-Bit Foreground Color (Grayscale)',
|
192
|
+
)
|
188
193
|
FG8_RGB = ControlSequence(
|
189
194
|
lambda r, g, b: CSI + '38;5;' + str(36 * r + 6 * g + b) + 'm',
|
190
|
-
'8-Bit Foreground Color (RGB)'
|
195
|
+
'8-Bit Foreground Color (RGB)',
|
196
|
+
)
|
191
197
|
|
192
198
|
BG8 = ControlSequence(
|
193
199
|
lambda n: CSI + '48;5;' + str(n) + 'm',
|
194
|
-
'8-Bit Background Color'
|
200
|
+
'8-Bit Background Color',
|
201
|
+
)
|
195
202
|
BG8_STANDARD = ControlSequence(
|
196
203
|
lambda n: CSI + '48;5;' + _clamp_ofs(n, 8, 0) + 'm',
|
197
|
-
'8-Bit Background Color (Standard)'
|
204
|
+
'8-Bit Background Color (Standard)',
|
205
|
+
)
|
198
206
|
BG8_HIGH_INTENSITY = ControlSequence(
|
199
207
|
lambda n: CSI + '48;5;' + _clamp_ofs(n, 8, 8) + 'm',
|
200
|
-
'8-Bit Background Color (High Intensity)'
|
208
|
+
'8-Bit Background Color (High Intensity)',
|
209
|
+
)
|
201
210
|
BG8_216 = ControlSequence(
|
202
211
|
lambda n: CSI + '48;5;' + _clamp_ofs(n, 216, 16) + 'm',
|
203
|
-
'8-Bit Background Color (High Intensity)'
|
212
|
+
'8-Bit Background Color (High Intensity)',
|
213
|
+
)
|
204
214
|
BG8_GRAYSCALE = ControlSequence(
|
205
215
|
lambda n: CSI + '48;5;' + _clamp_ofs(n, 24, 232) + 'm',
|
206
|
-
'8-Bit Background Color (Grayscale)'
|
216
|
+
'8-Bit Background Color (Grayscale)',
|
217
|
+
)
|
207
218
|
BG8_RGB = ControlSequence(
|
208
219
|
lambda r, g, b: CSI + '48;5;' + str(36 * r + 6 * g + b) + 'm',
|
209
|
-
'8-Bit Background Color (RGB)'
|
220
|
+
'8-Bit Background Color (RGB)',
|
221
|
+
)
|
210
222
|
|
211
223
|
FG24_RGB = ControlSequence(
|
212
224
|
lambda r, g, b: CSI + '38;2;' + str(r) + ';' + str(g) + ';' + str(b) + 'm',
|
213
|
-
'24-Bit Foreground Color (RGB)'
|
225
|
+
'24-Bit Foreground Color (RGB)',
|
226
|
+
)
|
214
227
|
BG24_RGB = ControlSequence(
|
215
228
|
lambda r, g, b: CSI + '48;2;' + str(r) + ';' + str(g) + ';' + str(b) + 'm',
|
216
|
-
'24-Bit Background Color (RGB)'
|
229
|
+
'24-Bit Background Color (RGB)',
|
230
|
+
)
|
231
|
+
|
217
232
|
|
218
233
|
##
|
219
234
|
|
omlish/testing/pytest/marks.py
CHANGED
@@ -7,9 +7,9 @@ from .plugins.managermarks import ManagerMark # noqa
|
|
7
7
|
|
8
8
|
|
9
9
|
if ta.TYPE_CHECKING:
|
10
|
-
from ...asyncs import
|
10
|
+
from ...asyncs.asyncio import all as aiu
|
11
11
|
else:
|
12
|
-
aiu = lang.proxy_import('...asyncs.asyncio', __package__)
|
12
|
+
aiu = lang.proxy_import('...asyncs.asyncio.all', __package__)
|
13
13
|
|
14
14
|
|
15
15
|
class drain_asyncio(ManagerMark): # noqa
|
@@ -142,7 +142,12 @@ class AsyncsPlugin:
|
|
142
142
|
if len(bes) > 1 and set(bes) != {'trio', 'trio_asyncio'}:
|
143
143
|
raise Exception(f'{item.nodeid}: multiple async backends specified: {bes}')
|
144
144
|
elif is_async_function(item.obj) and not bes:
|
145
|
-
|
145
|
+
from _pytest.unittest import UnitTestCase # noqa
|
146
|
+
if isinstance(item.parent, UnitTestCase):
|
147
|
+
# unittest handles these itself.
|
148
|
+
pass
|
149
|
+
else:
|
150
|
+
raise Exception(f'{item.nodeid}: async def function and no async plugin specified')
|
146
151
|
|
147
152
|
if 'trio_asyncio' in bes:
|
148
153
|
obj = item.obj
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: omlish
|
3
|
-
Version: 0.0.0.
|
3
|
+
Version: 0.0.0.dev177
|
4
4
|
Summary: omlish
|
5
5
|
Author: wrmsr
|
6
6
|
License: BSD-3-Clause
|
@@ -13,7 +13,7 @@ Classifier: Operating System :: POSIX
|
|
13
13
|
Requires-Python: >=3.12
|
14
14
|
License-File: LICENSE
|
15
15
|
Provides-Extra: all
|
16
|
-
Requires-Dist: anyio~=4.
|
16
|
+
Requires-Dist: anyio~=4.7; extra == "all"
|
17
17
|
Requires-Dist: sniffio~=1.3; extra == "all"
|
18
18
|
Requires-Dist: greenlet~=3.1; extra == "all"
|
19
19
|
Requires-Dist: trio~=0.27; extra == "all"
|
@@ -21,6 +21,7 @@ Requires-Dist: trio-asyncio~=0.15; extra == "all"
|
|
21
21
|
Requires-Dist: lz4~=4.3; extra == "all"
|
22
22
|
Requires-Dist: python-snappy~=0.7; extra == "all"
|
23
23
|
Requires-Dist: zstandard~=0.23; extra == "all"
|
24
|
+
Requires-Dist: brotli~=1.1; extra == "all"
|
24
25
|
Requires-Dist: asttokens~=3.0; extra == "all"
|
25
26
|
Requires-Dist: executing~=2.1; extra == "all"
|
26
27
|
Requires-Dist: psutil~=6.0; extra == "all"
|
@@ -43,7 +44,7 @@ Requires-Dist: apsw~=3.47; extra == "all"
|
|
43
44
|
Requires-Dist: sqlean.py~=3.45; extra == "all"
|
44
45
|
Requires-Dist: duckdb~=1.1; extra == "all"
|
45
46
|
Requires-Dist: pytest~=8.0; extra == "all"
|
46
|
-
Requires-Dist: anyio~=4.
|
47
|
+
Requires-Dist: anyio~=4.7; extra == "all"
|
47
48
|
Requires-Dist: sniffio~=1.3; extra == "all"
|
48
49
|
Requires-Dist: asttokens~=3.0; extra == "all"
|
49
50
|
Requires-Dist: executing~=2.1; extra == "all"
|
@@ -51,7 +52,7 @@ Requires-Dist: orjson~=3.10; extra == "all"
|
|
51
52
|
Requires-Dist: pyyaml~=6.0; extra == "all"
|
52
53
|
Requires-Dist: wrapt~=1.14; extra == "all"
|
53
54
|
Provides-Extra: async
|
54
|
-
Requires-Dist: anyio~=4.
|
55
|
+
Requires-Dist: anyio~=4.7; extra == "async"
|
55
56
|
Requires-Dist: sniffio~=1.3; extra == "async"
|
56
57
|
Requires-Dist: greenlet~=3.1; extra == "async"
|
57
58
|
Requires-Dist: trio~=0.27; extra == "async"
|
@@ -60,6 +61,7 @@ Provides-Extra: compress
|
|
60
61
|
Requires-Dist: lz4~=4.3; extra == "compress"
|
61
62
|
Requires-Dist: python-snappy~=0.7; extra == "compress"
|
62
63
|
Requires-Dist: zstandard~=0.23; extra == "compress"
|
64
|
+
Requires-Dist: brotli~=1.1; extra == "compress"
|
63
65
|
Provides-Extra: diag
|
64
66
|
Requires-Dist: asttokens~=3.0; extra == "diag"
|
65
67
|
Requires-Dist: executing~=2.1; extra == "diag"
|
@@ -91,7 +93,7 @@ Requires-Dist: duckdb~=1.1; extra == "sqldrivers"
|
|
91
93
|
Provides-Extra: testing
|
92
94
|
Requires-Dist: pytest~=8.0; extra == "testing"
|
93
95
|
Provides-Extra: plus
|
94
|
-
Requires-Dist: anyio~=4.
|
96
|
+
Requires-Dist: anyio~=4.7; extra == "plus"
|
95
97
|
Requires-Dist: sniffio~=1.3; extra == "plus"
|
96
98
|
Requires-Dist: asttokens~=3.0; extra == "plus"
|
97
99
|
Requires-Dist: executing~=2.1; extra == "plus"
|