omlish 0.0.0.dev132__py3-none-any.whl → 0.0.0.dev177__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
Files changed (210) hide show
  1. omlish/.manifests.json +265 -7
  2. omlish/__about__.py +7 -5
  3. omlish/antlr/_runtime/__init__.py +0 -22
  4. omlish/antlr/_runtime/_all.py +24 -0
  5. omlish/antlr/_runtime/atn/ParserATNSimulator.py +1 -1
  6. omlish/antlr/_runtime/dfa/DFASerializer.py +1 -1
  7. omlish/antlr/_runtime/error/DiagnosticErrorListener.py +2 -1
  8. omlish/antlr/_runtime/xpath/XPath.py +7 -1
  9. omlish/antlr/_runtime/xpath/XPathLexer.py +1 -1
  10. omlish/antlr/delimit.py +106 -0
  11. omlish/antlr/dot.py +31 -0
  12. omlish/antlr/errors.py +11 -0
  13. omlish/antlr/input.py +96 -0
  14. omlish/antlr/parsing.py +19 -0
  15. omlish/antlr/runtime.py +102 -0
  16. omlish/antlr/utils.py +38 -0
  17. omlish/argparse/all.py +45 -0
  18. omlish/{argparse.py → argparse/cli.py} +112 -107
  19. omlish/asyncs/__init__.py +0 -35
  20. omlish/asyncs/all.py +35 -0
  21. omlish/asyncs/asyncio/all.py +7 -0
  22. omlish/asyncs/asyncio/channels.py +40 -0
  23. omlish/asyncs/asyncio/streams.py +45 -0
  24. omlish/asyncs/asyncio/subprocesses.py +238 -0
  25. omlish/asyncs/asyncio/timeouts.py +16 -0
  26. omlish/asyncs/bluelet/LICENSE +6 -0
  27. omlish/asyncs/bluelet/all.py +67 -0
  28. omlish/asyncs/bluelet/api.py +23 -0
  29. omlish/asyncs/bluelet/core.py +178 -0
  30. omlish/asyncs/bluelet/events.py +78 -0
  31. omlish/asyncs/bluelet/files.py +80 -0
  32. omlish/asyncs/bluelet/runner.py +416 -0
  33. omlish/asyncs/bluelet/sockets.py +214 -0
  34. omlish/bootstrap/sys.py +3 -3
  35. omlish/cached.py +2 -2
  36. omlish/check.py +49 -460
  37. omlish/codecs/__init__.py +72 -0
  38. omlish/codecs/base.py +106 -0
  39. omlish/codecs/bytes.py +119 -0
  40. omlish/codecs/chain.py +23 -0
  41. omlish/codecs/funcs.py +39 -0
  42. omlish/codecs/registry.py +139 -0
  43. omlish/codecs/standard.py +4 -0
  44. omlish/codecs/text.py +217 -0
  45. omlish/collections/cache/impl.py +50 -57
  46. omlish/collections/coerce.py +1 -0
  47. omlish/collections/mappings.py +1 -1
  48. omlish/configs/flattening.py +1 -1
  49. omlish/defs.py +1 -1
  50. omlish/diag/_pycharm/runhack.py +8 -2
  51. omlish/diag/procfs.py +8 -8
  52. omlish/docker/__init__.py +0 -36
  53. omlish/docker/all.py +31 -0
  54. omlish/docker/consts.py +4 -0
  55. omlish/{lite/docker.py → docker/detect.py} +18 -0
  56. omlish/docker/{helpers.py → timebomb.py} +0 -21
  57. omlish/formats/cbor.py +31 -0
  58. omlish/formats/cloudpickle.py +31 -0
  59. omlish/formats/codecs.py +93 -0
  60. omlish/formats/json/codecs.py +29 -0
  61. omlish/formats/json/delimted.py +4 -0
  62. omlish/formats/json/stream/errors.py +2 -0
  63. omlish/formats/json/stream/lex.py +12 -6
  64. omlish/formats/json/stream/parse.py +38 -22
  65. omlish/formats/json5.py +31 -0
  66. omlish/formats/pickle.py +31 -0
  67. omlish/formats/repr.py +25 -0
  68. omlish/formats/toml.py +17 -0
  69. omlish/formats/yaml.py +25 -0
  70. omlish/funcs/__init__.py +0 -0
  71. omlish/{genmachine.py → funcs/genmachine.py} +5 -4
  72. omlish/{matchfns.py → funcs/match.py} +1 -1
  73. omlish/funcs/pairs.py +215 -0
  74. omlish/http/__init__.py +0 -48
  75. omlish/http/all.py +48 -0
  76. omlish/http/coro/__init__.py +0 -0
  77. omlish/{lite/fdio/corohttp.py → http/coro/fdio.py} +21 -19
  78. omlish/{lite/http/coroserver.py → http/coro/server.py} +20 -21
  79. omlish/{lite/http → http}/handlers.py +3 -2
  80. omlish/{lite/http → http}/parsing.py +1 -0
  81. omlish/http/sessions.py +1 -1
  82. omlish/{lite/http → http}/versions.py +1 -0
  83. omlish/inject/managed.py +2 -2
  84. omlish/io/__init__.py +0 -3
  85. omlish/{lite/io.py → io/buffers.py} +8 -9
  86. omlish/io/compress/__init__.py +9 -0
  87. omlish/io/compress/abc.py +104 -0
  88. omlish/io/compress/adapters.py +148 -0
  89. omlish/io/compress/base.py +24 -0
  90. omlish/io/compress/brotli.py +47 -0
  91. omlish/io/compress/bz2.py +61 -0
  92. omlish/io/compress/codecs.py +78 -0
  93. omlish/io/compress/gzip.py +350 -0
  94. omlish/io/compress/lz4.py +91 -0
  95. omlish/io/compress/lzma.py +81 -0
  96. omlish/io/compress/snappy.py +34 -0
  97. omlish/io/compress/zlib.py +74 -0
  98. omlish/io/compress/zstd.py +44 -0
  99. omlish/io/fdio/__init__.py +1 -0
  100. omlish/{lite → io}/fdio/handlers.py +5 -5
  101. omlish/{lite → io}/fdio/kqueue.py +8 -8
  102. omlish/{lite → io}/fdio/manager.py +7 -7
  103. omlish/{lite → io}/fdio/pollers.py +13 -13
  104. omlish/io/generators/__init__.py +56 -0
  105. omlish/io/generators/consts.py +1 -0
  106. omlish/io/generators/direct.py +13 -0
  107. omlish/io/generators/readers.py +189 -0
  108. omlish/io/generators/stepped.py +191 -0
  109. omlish/io/pyio.py +5 -2
  110. omlish/iterators/__init__.py +24 -0
  111. omlish/iterators/iterators.py +132 -0
  112. omlish/iterators/recipes.py +18 -0
  113. omlish/iterators/tools.py +96 -0
  114. omlish/iterators/unique.py +67 -0
  115. omlish/lang/__init__.py +13 -1
  116. omlish/lang/functions.py +11 -2
  117. omlish/lang/generators.py +243 -0
  118. omlish/lang/iterables.py +46 -49
  119. omlish/lang/maybes.py +4 -4
  120. omlish/lite/cached.py +39 -6
  121. omlish/lite/check.py +438 -75
  122. omlish/lite/contextmanagers.py +17 -4
  123. omlish/lite/dataclasses.py +42 -0
  124. omlish/lite/inject.py +28 -45
  125. omlish/lite/logs.py +0 -270
  126. omlish/lite/marshal.py +309 -144
  127. omlish/lite/pycharm.py +47 -0
  128. omlish/lite/reflect.py +33 -0
  129. omlish/lite/resources.py +8 -0
  130. omlish/lite/runtime.py +4 -4
  131. omlish/lite/shlex.py +12 -0
  132. omlish/lite/socketserver.py +2 -2
  133. omlish/lite/strings.py +31 -0
  134. omlish/logs/__init__.py +0 -32
  135. omlish/logs/{_abc.py → abc.py} +0 -1
  136. omlish/logs/all.py +37 -0
  137. omlish/logs/{formatters.py → color.py} +1 -2
  138. omlish/logs/configs.py +7 -38
  139. omlish/logs/filters.py +10 -0
  140. omlish/logs/handlers.py +4 -1
  141. omlish/logs/json.py +56 -0
  142. omlish/logs/proxy.py +99 -0
  143. omlish/logs/standard.py +128 -0
  144. omlish/logs/utils.py +2 -2
  145. omlish/manifests/__init__.py +2 -0
  146. omlish/manifests/load.py +209 -0
  147. omlish/manifests/types.py +17 -0
  148. omlish/marshal/base.py +1 -1
  149. omlish/marshal/factories.py +1 -1
  150. omlish/marshal/forbidden.py +1 -1
  151. omlish/marshal/iterables.py +1 -1
  152. omlish/marshal/literals.py +50 -0
  153. omlish/marshal/mappings.py +1 -1
  154. omlish/marshal/maybes.py +1 -1
  155. omlish/marshal/standard.py +5 -1
  156. omlish/marshal/unions.py +1 -1
  157. omlish/os/__init__.py +0 -0
  158. omlish/os/atomics.py +205 -0
  159. omlish/os/deathsig.py +23 -0
  160. omlish/{os.py → os/files.py} +0 -9
  161. omlish/{lite → os}/journald.py +2 -1
  162. omlish/os/linux.py +484 -0
  163. omlish/os/paths.py +36 -0
  164. omlish/{lite → os}/pidfile.py +1 -0
  165. omlish/os/sizes.py +9 -0
  166. omlish/reflect/__init__.py +3 -0
  167. omlish/reflect/subst.py +2 -1
  168. omlish/reflect/types.py +126 -44
  169. omlish/secrets/pwhash.py +1 -1
  170. omlish/secrets/subprocesses.py +3 -1
  171. omlish/specs/jsonrpc/marshal.py +1 -1
  172. omlish/specs/openapi/marshal.py +1 -1
  173. omlish/sql/alchemy/asyncs.py +1 -1
  174. omlish/sql/queries/__init__.py +9 -1
  175. omlish/sql/queries/building.py +3 -0
  176. omlish/sql/queries/exprs.py +10 -27
  177. omlish/sql/queries/idents.py +48 -10
  178. omlish/sql/queries/names.py +80 -13
  179. omlish/sql/queries/params.py +64 -0
  180. omlish/sql/queries/rendering.py +1 -1
  181. omlish/subprocesses.py +340 -0
  182. omlish/term.py +29 -14
  183. omlish/testing/pytest/marks.py +2 -2
  184. omlish/testing/pytest/plugins/asyncs.py +6 -1
  185. omlish/testing/pytest/plugins/logging.py +1 -1
  186. omlish/testing/pytest/plugins/switches.py +1 -1
  187. {omlish-0.0.0.dev132.dist-info → omlish-0.0.0.dev177.dist-info}/METADATA +13 -11
  188. {omlish-0.0.0.dev132.dist-info → omlish-0.0.0.dev177.dist-info}/RECORD +200 -117
  189. omlish/fnpairs.py +0 -496
  190. omlish/formats/json/cli/__main__.py +0 -11
  191. omlish/formats/json/cli/cli.py +0 -298
  192. omlish/formats/json/cli/formats.py +0 -71
  193. omlish/formats/json/cli/io.py +0 -74
  194. omlish/formats/json/cli/parsing.py +0 -82
  195. omlish/formats/json/cli/processing.py +0 -48
  196. omlish/formats/json/cli/rendering.py +0 -92
  197. omlish/iterators.py +0 -300
  198. omlish/lite/subprocesses.py +0 -130
  199. /omlish/{formats/json/cli → argparse}/__init__.py +0 -0
  200. /omlish/{lite/fdio → asyncs/asyncio}/__init__.py +0 -0
  201. /omlish/asyncs/{asyncio.py → asyncio/asyncio.py} +0 -0
  202. /omlish/{lite/http → asyncs/bluelet}/__init__.py +0 -0
  203. /omlish/collections/{_abc.py → abc.py} +0 -0
  204. /omlish/{fnpipes.py → funcs/pipes.py} +0 -0
  205. /omlish/io/{_abc.py → abc.py} +0 -0
  206. /omlish/sql/{_abc.py → abc.py} +0 -0
  207. {omlish-0.0.0.dev132.dist-info → omlish-0.0.0.dev177.dist-info}/LICENSE +0 -0
  208. {omlish-0.0.0.dev132.dist-info → omlish-0.0.0.dev177.dist-info}/WHEEL +0 -0
  209. {omlish-0.0.0.dev132.dist-info → omlish-0.0.0.dev177.dist-info}/entry_points.txt +0 -0
  210. {omlish-0.0.0.dev132.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()
@@ -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
 
@@ -7,9 +7,9 @@ from .plugins.managermarks import ManagerMark # noqa
7
7
 
8
8
 
9
9
  if ta.TYPE_CHECKING:
10
- from ...asyncs import asyncio as aiu
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
- raise Exception(f'{item.nodeid}: async def function and no async plugin specified')
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,4 +1,4 @@
1
- from .... import logs
1
+ from ....logs import all as logs
2
2
  from ._registry import register
3
3
 
4
4
 
@@ -10,8 +10,8 @@ import pytest
10
10
 
11
11
  from .... import check
12
12
  from .... import collections as col
13
- from .... import docker
14
13
  from .... import lang
14
+ from ....docker import all as docker
15
15
  from ._registry import register
16
16
 
17
17
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: omlish
3
- Version: 0.0.0.dev132
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.6; extra == "all"
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,7 +21,8 @@ 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: asttokens~=2.4; extra == "all"
24
+ Requires-Dist: brotli~=1.1; extra == "all"
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"
27
28
  Requires-Dist: orjson~=3.10; extra == "all"
@@ -30,7 +31,7 @@ Requires-Dist: json5~=0.9; extra == "all"
30
31
  Requires-Dist: pyyaml~=6.0; extra == "all"
31
32
  Requires-Dist: cbor2~=5.6; extra == "all"
32
33
  Requires-Dist: cloudpickle~=3.1; extra == "all"
33
- Requires-Dist: httpx[http2]~=0.27; extra == "all"
34
+ Requires-Dist: httpx[http2]~=0.28; extra == "all"
34
35
  Requires-Dist: wrapt~=1.14; extra == "all"
35
36
  Requires-Dist: cryptography~=43.0; extra == "all"
36
37
  Requires-Dist: sqlalchemy[asyncio]~=2.0; extra == "all"
@@ -43,15 +44,15 @@ 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.6; extra == "all"
47
+ Requires-Dist: anyio~=4.7; extra == "all"
47
48
  Requires-Dist: sniffio~=1.3; extra == "all"
48
- Requires-Dist: asttokens~=2.4; extra == "all"
49
+ Requires-Dist: asttokens~=3.0; extra == "all"
49
50
  Requires-Dist: executing~=2.1; extra == "all"
50
51
  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.6; extra == "async"
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,8 +61,9 @@ 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
- Requires-Dist: asttokens~=2.4; extra == "diag"
66
+ Requires-Dist: asttokens~=3.0; extra == "diag"
65
67
  Requires-Dist: executing~=2.1; extra == "diag"
66
68
  Requires-Dist: psutil~=6.0; extra == "diag"
67
69
  Provides-Extra: formats
@@ -72,7 +74,7 @@ Requires-Dist: pyyaml~=6.0; extra == "formats"
72
74
  Requires-Dist: cbor2~=5.6; extra == "formats"
73
75
  Requires-Dist: cloudpickle~=3.1; extra == "formats"
74
76
  Provides-Extra: http
75
- Requires-Dist: httpx[http2]~=0.27; extra == "http"
77
+ Requires-Dist: httpx[http2]~=0.28; extra == "http"
76
78
  Provides-Extra: misc
77
79
  Requires-Dist: wrapt~=1.14; extra == "misc"
78
80
  Provides-Extra: secrets
@@ -91,9 +93,9 @@ 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.6; extra == "plus"
96
+ Requires-Dist: anyio~=4.7; extra == "plus"
95
97
  Requires-Dist: sniffio~=1.3; extra == "plus"
96
- Requires-Dist: asttokens~=2.4; extra == "plus"
98
+ Requires-Dist: asttokens~=3.0; extra == "plus"
97
99
  Requires-Dist: executing~=2.1; extra == "plus"
98
100
  Requires-Dist: orjson~=3.10; extra == "plus"
99
101
  Requires-Dist: pyyaml~=6.0; extra == "plus"