omlish 0.0.0.dev156__py3-none-any.whl → 0.0.0.dev158__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 CHANGED
@@ -1,5 +1,5 @@
1
- __version__ = '0.0.0.dev156'
2
- __revision__ = '594c80ed50a0c5515f35cac4b31a4ed482993a4b'
1
+ __version__ = '0.0.0.dev158'
2
+ __revision__ = 'af6daf87e05e81846b224e4d0031cd101a27158b'
3
3
 
4
4
 
5
5
  #
omlish/argparse/cli.py CHANGED
@@ -14,6 +14,8 @@ import sys
14
14
  import typing as ta
15
15
 
16
16
  from ..lite.check import check
17
+ from ..lite.reflect import get_optional_alias_arg
18
+ from ..lite.reflect import is_optional_alias
17
19
 
18
20
 
19
21
  T = ta.TypeVar('T')
@@ -120,6 +122,8 @@ def _get_argparse_arg_ann_kwargs(ann: ta.Any) -> ta.Mapping[str, ta.Any]:
120
122
  return {'action': 'store_true'}
121
123
  elif ann is list:
122
124
  return {'action': 'append'}
125
+ elif is_optional_alias(ann):
126
+ return _get_argparse_arg_ann_kwargs(get_optional_alias_arg(ann))
123
127
  else:
124
128
  raise TypeError(ann)
125
129
 
@@ -1,17 +1,18 @@
1
1
  # ruff: noqa: UP006 UP007
2
+ # @omlish-lite
2
3
  import asyncio.base_subprocess
3
4
  import asyncio.subprocess
4
5
  import contextlib
5
6
  import dataclasses as dc
6
7
  import functools
8
+ import logging
7
9
  import subprocess
8
10
  import sys
9
11
  import typing as ta
10
12
 
11
- from ...asyncs.asyncio.timeouts import asyncio_maybe_timeout
12
- from ..check import check
13
- from ..logs import log
14
- from ..subprocesses import AbstractSubprocesses
13
+ from ...lite.check import check
14
+ from ...subprocesses import AbstractAsyncSubprocesses
15
+ from .timeouts import asyncio_maybe_timeout
15
16
 
16
17
 
17
18
  T = ta.TypeVar('T')
@@ -25,6 +26,8 @@ class AsyncioProcessCommunicator:
25
26
  self,
26
27
  proc: asyncio.subprocess.Process,
27
28
  loop: ta.Optional[ta.Any] = None,
29
+ *,
30
+ log: ta.Optional[logging.Logger] = None,
28
31
  ) -> None:
29
32
  super().__init__()
30
33
 
@@ -33,6 +36,7 @@ class AsyncioProcessCommunicator:
33
36
 
34
37
  self._proc = proc
35
38
  self._loop = loop
39
+ self._log = log
36
40
 
37
41
  self._transport: asyncio.base_subprocess.BaseSubprocessTransport = check.isinstance(
38
42
  proc._transport, # type: ignore # noqa
@@ -48,19 +52,19 @@ class AsyncioProcessCommunicator:
48
52
  try:
49
53
  if input is not None:
50
54
  stdin.write(input)
51
- if self._debug:
52
- log.debug('%r communicate: feed stdin (%s bytes)', self, len(input))
55
+ if self._debug and self._log is not None:
56
+ self._log.debug('%r communicate: feed stdin (%s bytes)', self, len(input))
53
57
 
54
58
  await stdin.drain()
55
59
 
56
60
  except (BrokenPipeError, ConnectionResetError) as exc:
57
61
  # communicate() ignores BrokenPipeError and ConnectionResetError. write() and drain() can raise these
58
62
  # exceptions.
59
- if self._debug:
60
- log.debug('%r communicate: stdin got %r', self, exc)
63
+ if self._debug and self._log is not None:
64
+ self._log.debug('%r communicate: stdin got %r', self, exc)
61
65
 
62
- if self._debug:
63
- log.debug('%r communicate: close stdin', self)
66
+ if self._debug and self._log is not None:
67
+ self._log.debug('%r communicate: close stdin', self)
64
68
 
65
69
  stdin.close()
66
70
 
@@ -76,15 +80,15 @@ class AsyncioProcessCommunicator:
76
80
  check.equal(fd, 1)
77
81
  stream = check.not_none(self._proc.stdout)
78
82
 
79
- if self._debug:
83
+ if self._debug and self._log is not None:
80
84
  name = 'stdout' if fd == 1 else 'stderr'
81
- log.debug('%r communicate: read %s', self, name)
85
+ self._log.debug('%r communicate: read %s', self, name)
82
86
 
83
87
  output = await stream.read()
84
88
 
85
- if self._debug:
89
+ if self._debug and self._log is not None:
86
90
  name = 'stdout' if fd == 1 else 'stderr'
87
- log.debug('%r communicate: close %s', self, name)
91
+ self._log.debug('%r communicate: close %s', self, name)
88
92
 
89
93
  transport.close()
90
94
 
@@ -133,7 +137,7 @@ class AsyncioProcessCommunicator:
133
137
  ##
134
138
 
135
139
 
136
- class AsyncioSubprocesses(AbstractSubprocesses):
140
+ class AsyncioSubprocesses(AbstractAsyncSubprocesses):
137
141
  async def communicate(
138
142
  self,
139
143
  proc: asyncio.subprocess.Process,
@@ -230,44 +234,5 @@ class AsyncioSubprocesses(AbstractSubprocesses):
230
234
  with self.prepare_and_wrap(*cmd, stdout=subprocess.PIPE, check=True, **kwargs) as (cmd, kwargs): # noqa
231
235
  return check.not_none((await self.run(*cmd, **kwargs)).stdout)
232
236
 
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()
271
-
272
237
 
273
238
  asyncio_subprocesses = AsyncioSubprocesses()
omlish/bootstrap/sys.py CHANGED
@@ -21,8 +21,8 @@ from .base import SimpleBootstrap
21
21
 
22
22
  if ta.TYPE_CHECKING:
23
23
  from .. import libc
24
- from .. import logs
25
24
  from ..formats import dotenv
25
+ from ..logs import all as logs
26
26
  from ..os import pidfile
27
27
 
28
28
  else:
@@ -1,14 +1,15 @@
1
1
  # ruff: noqa: UP006 UP007
2
+ # @omlish-lite
2
3
  import socket
3
4
  import typing as ta
4
5
 
5
- from ...http.coroserver import CoroHttpServer
6
- from ...http.handlers import HttpHandler
6
+ from ...io.buffers import IncrementalWriteBuffer
7
+ from ...io.buffers import ReadableListBuffer
8
+ from ...io.fdio.handlers import SocketFdioHandler
7
9
  from ...lite.check import check
8
10
  from ...lite.socket import SocketAddress
9
- from ..buffers import IncrementalWriteBuffer
10
- from ..buffers import ReadableListBuffer
11
- from .handlers import SocketFdioHandler
11
+ from ..handlers import HttpHandler
12
+ from .server import CoroHttpServer
12
13
 
13
14
 
14
15
  class CoroHttpServerConnectionFdioHandler(SocketFdioHandler):
@@ -63,18 +63,18 @@ import textwrap
63
63
  import time
64
64
  import typing as ta
65
65
 
66
- from ..lite.check import check
67
- from ..lite.socket import SocketAddress
68
- from ..lite.socket import SocketHandler
69
- from .handlers import HttpHandler
70
- from .handlers import HttpHandlerRequest
71
- from .handlers import UnsupportedMethodHttpHandlerError
72
- from .parsing import EmptyParsedHttpResult
73
- from .parsing import HttpRequestParser
74
- from .parsing import ParsedHttpRequest
75
- from .parsing import ParseHttpRequestError
76
- from .versions import HttpProtocolVersion
77
- from .versions import HttpProtocolVersions
66
+ from ...lite.check import check
67
+ from ...lite.socket import SocketAddress
68
+ from ...lite.socket import SocketHandler
69
+ from ..handlers import HttpHandler
70
+ from ..handlers import HttpHandlerRequest
71
+ from ..handlers import UnsupportedMethodHttpHandlerError
72
+ from ..parsing import EmptyParsedHttpResult
73
+ from ..parsing import HttpRequestParser
74
+ from ..parsing import ParsedHttpRequest
75
+ from ..parsing import ParseHttpRequestError
76
+ from ..versions import HttpProtocolVersion
77
+ from ..versions import HttpProtocolVersions
78
78
 
79
79
 
80
80
  CoroHttpServerFactory = ta.Callable[[SocketAddress], 'CoroHttpServer']
omlish/http/handlers.py CHANGED
@@ -8,7 +8,7 @@ from ..lite.socket import SocketAddress
8
8
  from .parsing import HttpHeaders
9
9
 
10
10
 
11
- HttpHandler = ta.Callable[['HttpHandlerRequest'], 'HttpHandlerResponse']
11
+ HttpHandler = ta.Callable[['HttpHandlerRequest'], 'HttpHandlerResponse'] # ta.TypeAlias
12
12
 
13
13
 
14
14
  @dc.dataclass(frozen=True)
omlish/lite/cached.py CHANGED
@@ -35,8 +35,8 @@ class _CachedNullary(_AbstractCachedNullary):
35
35
  return self._value
36
36
 
37
37
 
38
- def cached_nullary(fn): # ta.Callable[..., T]) -> ta.Callable[..., T]:
39
- return _CachedNullary(fn)
38
+ def cached_nullary(fn: CallableT) -> CallableT:
39
+ return _CachedNullary(fn) # type: ignore
40
40
 
41
41
 
42
42
  def static_init(fn: CallableT) -> CallableT:
omlish/lite/logs.py CHANGED
@@ -1,274 +1,4 @@
1
- """
2
- TODO:
3
- - translate json keys
4
- - debug
5
- """
6
- # ruff: noqa: UP006 UP007 N802
7
- import contextlib
8
- import datetime
9
1
  import logging
10
- import threading
11
- import typing as ta
12
-
13
- from .json import json_dumps_compact
14
2
 
15
3
 
16
4
  log = logging.getLogger(__name__)
17
-
18
-
19
- ##
20
-
21
-
22
- class TidLogFilter(logging.Filter):
23
-
24
- def filter(self, record):
25
- record.tid = threading.get_native_id()
26
- return True
27
-
28
-
29
- ##
30
-
31
-
32
- class JsonLogFormatter(logging.Formatter):
33
-
34
- KEYS: ta.Mapping[str, bool] = {
35
- 'name': False,
36
- 'msg': False,
37
- 'args': False,
38
- 'levelname': False,
39
- 'levelno': False,
40
- 'pathname': False,
41
- 'filename': False,
42
- 'module': False,
43
- 'exc_info': True,
44
- 'exc_text': True,
45
- 'stack_info': True,
46
- 'lineno': False,
47
- 'funcName': False,
48
- 'created': False,
49
- 'msecs': False,
50
- 'relativeCreated': False,
51
- 'thread': False,
52
- 'threadName': False,
53
- 'processName': False,
54
- 'process': False,
55
- }
56
-
57
- def format(self, record: logging.LogRecord) -> str:
58
- dct = {
59
- k: v
60
- for k, o in self.KEYS.items()
61
- for v in [getattr(record, k)]
62
- if not (o and v is None)
63
- }
64
- return json_dumps_compact(dct)
65
-
66
-
67
- ##
68
-
69
-
70
- STANDARD_LOG_FORMAT_PARTS = [
71
- ('asctime', '%(asctime)-15s'),
72
- ('process', 'pid=%(process)-6s'),
73
- ('thread', 'tid=%(thread)x'),
74
- ('levelname', '%(levelname)s'),
75
- ('name', '%(name)s'),
76
- ('separator', '::'),
77
- ('message', '%(message)s'),
78
- ]
79
-
80
-
81
- class StandardLogFormatter(logging.Formatter):
82
-
83
- @staticmethod
84
- def build_log_format(parts: ta.Iterable[ta.Tuple[str, str]]) -> str:
85
- return ' '.join(v for k, v in parts)
86
-
87
- converter = datetime.datetime.fromtimestamp # type: ignore
88
-
89
- def formatTime(self, record, datefmt=None):
90
- ct = self.converter(record.created) # type: ignore
91
- if datefmt:
92
- return ct.strftime(datefmt) # noqa
93
- else:
94
- t = ct.strftime('%Y-%m-%d %H:%M:%S')
95
- return '%s.%03d' % (t, record.msecs) # noqa
96
-
97
-
98
- ##
99
-
100
-
101
- class ProxyLogFilterer(logging.Filterer):
102
- def __init__(self, underlying: logging.Filterer) -> None: # noqa
103
- self._underlying = underlying
104
-
105
- @property
106
- def underlying(self) -> logging.Filterer:
107
- return self._underlying
108
-
109
- @property
110
- def filters(self):
111
- return self._underlying.filters
112
-
113
- @filters.setter
114
- def filters(self, filters):
115
- self._underlying.filters = filters
116
-
117
- def addFilter(self, filter): # noqa
118
- self._underlying.addFilter(filter)
119
-
120
- def removeFilter(self, filter): # noqa
121
- self._underlying.removeFilter(filter)
122
-
123
- def filter(self, record):
124
- return self._underlying.filter(record)
125
-
126
-
127
- class ProxyLogHandler(ProxyLogFilterer, logging.Handler):
128
- def __init__(self, underlying: logging.Handler) -> None: # noqa
129
- ProxyLogFilterer.__init__(self, underlying)
130
-
131
- _underlying: logging.Handler
132
-
133
- @property
134
- def underlying(self) -> logging.Handler:
135
- return self._underlying
136
-
137
- def get_name(self):
138
- return self._underlying.get_name()
139
-
140
- def set_name(self, name):
141
- self._underlying.set_name(name)
142
-
143
- @property
144
- def name(self):
145
- return self._underlying.name
146
-
147
- @property
148
- def level(self):
149
- return self._underlying.level
150
-
151
- @level.setter
152
- def level(self, level):
153
- self._underlying.level = level
154
-
155
- @property
156
- def formatter(self):
157
- return self._underlying.formatter
158
-
159
- @formatter.setter
160
- def formatter(self, formatter):
161
- self._underlying.formatter = formatter
162
-
163
- def createLock(self):
164
- self._underlying.createLock()
165
-
166
- def acquire(self):
167
- self._underlying.acquire()
168
-
169
- def release(self):
170
- self._underlying.release()
171
-
172
- def setLevel(self, level):
173
- self._underlying.setLevel(level)
174
-
175
- def format(self, record):
176
- return self._underlying.format(record)
177
-
178
- def emit(self, record):
179
- self._underlying.emit(record)
180
-
181
- def handle(self, record):
182
- return self._underlying.handle(record)
183
-
184
- def setFormatter(self, fmt):
185
- self._underlying.setFormatter(fmt)
186
-
187
- def flush(self):
188
- self._underlying.flush()
189
-
190
- def close(self):
191
- self._underlying.close()
192
-
193
- def handleError(self, record):
194
- self._underlying.handleError(record)
195
-
196
-
197
- ##
198
-
199
-
200
- class StandardLogHandler(ProxyLogHandler):
201
- pass
202
-
203
-
204
- ##
205
-
206
-
207
- @contextlib.contextmanager
208
- def _locking_logging_module_lock() -> ta.Iterator[None]:
209
- if hasattr(logging, '_acquireLock'):
210
- logging._acquireLock() # noqa
211
- try:
212
- yield
213
- finally:
214
- logging._releaseLock() # type: ignore # noqa
215
-
216
- elif hasattr(logging, '_lock'):
217
- # https://github.com/python/cpython/commit/74723e11109a320e628898817ab449b3dad9ee96
218
- with logging._lock: # noqa
219
- yield
220
-
221
- else:
222
- raise Exception("Can't find lock in logging module")
223
-
224
-
225
- def configure_standard_logging(
226
- level: ta.Union[int, str] = logging.INFO,
227
- *,
228
- json: bool = False,
229
- target: ta.Optional[logging.Logger] = None,
230
- force: bool = False,
231
- handler_factory: ta.Optional[ta.Callable[[], logging.Handler]] = None,
232
- ) -> ta.Optional[StandardLogHandler]:
233
- with _locking_logging_module_lock():
234
- if target is None:
235
- target = logging.root
236
-
237
- #
238
-
239
- if not force:
240
- if any(isinstance(h, StandardLogHandler) for h in list(target.handlers)):
241
- return None
242
-
243
- #
244
-
245
- if handler_factory is not None:
246
- handler = handler_factory()
247
- else:
248
- handler = logging.StreamHandler()
249
-
250
- #
251
-
252
- formatter: logging.Formatter
253
- if json:
254
- formatter = JsonLogFormatter()
255
- else:
256
- formatter = StandardLogFormatter(StandardLogFormatter.build_log_format(STANDARD_LOG_FORMAT_PARTS))
257
- handler.setFormatter(formatter)
258
-
259
- #
260
-
261
- handler.addFilter(TidLogFilter())
262
-
263
- #
264
-
265
- target.addHandler(handler)
266
-
267
- #
268
-
269
- if level is not None:
270
- target.setLevel(level)
271
-
272
- #
273
-
274
- return StandardLogHandler(handler)
omlish/lite/marshal.py CHANGED
@@ -3,6 +3,7 @@ TODO:
3
3
  - pickle stdlib objs? have to pin to 3.8 pickle protocol, will be cross-version
4
4
  - namedtuple
5
5
  - literals
6
+ - newtypes?
6
7
  """
7
8
  # ruff: noqa: UP006 UP007
8
9
  import abc
omlish/logs/__init__.py CHANGED
@@ -1,32 +0,0 @@
1
- from .configs import ( # noqa
2
- configure_standard_logging,
3
- )
4
-
5
- from .formatters import ( # noqa
6
- ColorLogFormatter,
7
- )
8
-
9
- from .handlers import ( # noqa
10
- ListHandler,
11
- )
12
-
13
- from .utils import ( # noqa
14
- error_logging,
15
- )
16
-
17
-
18
- ##
19
-
20
-
21
- from ..lite.logs import ( # noqa
22
- TidLogFilter,
23
- JsonLogFormatter,
24
-
25
- STANDARD_LOG_FORMAT_PARTS,
26
- StandardLogFormatter,
27
-
28
- ProxyLogFilterer,
29
- ProxyLogHandler,
30
-
31
- StandardLogHandler,
32
- )
omlish/logs/all.py ADDED
@@ -0,0 +1,37 @@
1
+ from .color import ( # noqa
2
+ ColorLogFormatter,
3
+ )
4
+
5
+ from .filters import ( # noqa
6
+ TidLogFilter,
7
+ )
8
+
9
+ from .handlers import ( # noqa
10
+ ListHandler,
11
+ )
12
+
13
+ from .json import ( # noqa
14
+ JsonLogFormatter,
15
+ )
16
+
17
+ from .noisy import ( # noqa
18
+ silence_noisy_loggers,
19
+ )
20
+
21
+ from .proxy import ( # noqa
22
+ ProxyLogFilterer,
23
+ ProxyLogHandler,
24
+ )
25
+
26
+ from .standard import ( # noqa
27
+ STANDARD_LOG_FORMAT_PARTS,
28
+ StandardLogFormatter,
29
+
30
+ StandardLogHandler,
31
+
32
+ configure_standard_logging,
33
+ )
34
+
35
+ from .utils import ( # noqa
36
+ error_logging,
37
+ )
@@ -3,11 +3,10 @@ import logging
3
3
  import typing as ta
4
4
 
5
5
  from .. import term
6
- from ..lite.logs import StandardLogFormatter
6
+ from .standard import StandardLogFormatter
7
7
 
8
8
 
9
9
  class ColorLogFormatter(StandardLogFormatter):
10
-
11
10
  LEVEL_COLORS: ta.Mapping[int, term.SGRs.FG] = {
12
11
  logging.WARNING: term.SGRs.FG.BRIGHT_YELLOW,
13
12
  logging.ERROR: term.SGRs.FG.BRIGHT_RED,
omlish/logs/configs.py CHANGED
@@ -1,19 +1,17 @@
1
+ """
2
+ https://docs.python.org/3/howto/logging.html#configuring-logging
3
+ """
1
4
  import dataclasses as dc
2
- import logging
3
5
  import typing as ta
4
6
 
5
- from ..lite.logs import StandardLogHandler
6
- from ..lite.logs import configure_standard_logging as configure_lite_standard_logging
7
- from .noisy import silence_noisy_loggers
8
-
9
7
 
10
8
  ##
11
9
 
12
10
 
13
- FilterConfig = dict[str, ta.Any]
14
- FormatterConfig = dict[str, ta.Any]
15
- HandlerConfig = dict[str, ta.Any]
16
- LoggerConfig = dict[str, ta.Any]
11
+ FilterConfig: ta.TypeAlias = dict[str, ta.Any]
12
+ FormatterConfig: ta.TypeAlias = dict[str, ta.Any]
13
+ HandlerConfig: ta.TypeAlias = dict[str, ta.Any]
14
+ LoggerConfig: ta.TypeAlias = dict[str, ta.Any]
17
15
 
18
16
 
19
17
  @dc.dataclass()
@@ -26,32 +24,3 @@ class DictConfig:
26
24
  handlers: dict[str, HandlerConfig] = dc.field(default_factory=dict)
27
25
  loggers: dict[str, LoggerConfig] = dc.field(default_factory=dict)
28
26
  root: LoggerConfig | None = None
29
-
30
-
31
- ##
32
-
33
-
34
- def configure_standard_logging(
35
- level: ta.Any = None,
36
- *,
37
- json: bool = False,
38
- target: logging.Logger | None = None,
39
- force: bool = False,
40
- ) -> StandardLogHandler | None:
41
- handler = configure_lite_standard_logging(
42
- level,
43
- json=json,
44
- target=target,
45
- force=force,
46
- )
47
-
48
- if handler is None:
49
- return None
50
-
51
- #
52
-
53
- silence_noisy_loggers()
54
-
55
- #
56
-
57
- return handler
omlish/logs/filters.py ADDED
@@ -0,0 +1,10 @@
1
+ # ruff: noqa: UP006 UP007
2
+ # @omlish-lite
3
+ import logging
4
+ import threading
5
+
6
+
7
+ class TidLogFilter(logging.Filter):
8
+ def filter(self, record):
9
+ record.tid = threading.get_native_id()
10
+ return True
omlish/logs/handlers.py CHANGED
@@ -1,10 +1,13 @@
1
+ # ruff: noqa: UP006 UP007
2
+ # @omlish-lite
1
3
  import logging
4
+ import typing as ta
2
5
 
3
6
 
4
7
  class ListHandler(logging.Handler):
5
8
  def __init__(self) -> None:
6
9
  super().__init__()
7
- self.records: list[logging.LogRecord] = []
10
+ self.records: ta.List[logging.LogRecord] = []
8
11
 
9
12
  def emit(self, record: logging.LogRecord) -> None:
10
13
  self.records.append(record)
omlish/logs/json.py ADDED
@@ -0,0 +1,56 @@
1
+ # ruff: noqa: UP006 UP007
2
+ # @omlish-lite
3
+ """
4
+ TODO:
5
+ - translate json keys
6
+ """
7
+ import logging
8
+ import typing as ta
9
+
10
+ from ..lite.json import json_dumps_compact
11
+
12
+
13
+ class JsonLogFormatter(logging.Formatter):
14
+ KEYS: ta.Mapping[str, bool] = {
15
+ 'name': False,
16
+ 'msg': False,
17
+ 'args': False,
18
+ 'levelname': False,
19
+ 'levelno': False,
20
+ 'pathname': False,
21
+ 'filename': False,
22
+ 'module': False,
23
+ 'exc_info': True,
24
+ 'exc_text': True,
25
+ 'stack_info': True,
26
+ 'lineno': False,
27
+ 'funcName': False,
28
+ 'created': False,
29
+ 'msecs': False,
30
+ 'relativeCreated': False,
31
+ 'thread': False,
32
+ 'threadName': False,
33
+ 'processName': False,
34
+ 'process': False,
35
+ }
36
+
37
+ def __init__(
38
+ self,
39
+ *args: ta.Any,
40
+ json_dumps: ta.Optional[ta.Callable[[ta.Any], str]] = None,
41
+ **kwargs: ta.Any,
42
+ ) -> None:
43
+ super().__init__(*args, **kwargs)
44
+
45
+ if json_dumps is None:
46
+ json_dumps = json_dumps_compact
47
+ self._json_dumps = json_dumps
48
+
49
+ def format(self, record: logging.LogRecord) -> str:
50
+ dct = {
51
+ k: v
52
+ for k, o in self.KEYS.items()
53
+ for v in [getattr(record, k)]
54
+ if not (o and v is None)
55
+ }
56
+ return self._json_dumps(dct)
omlish/logs/proxy.py ADDED
@@ -0,0 +1,99 @@
1
+ # ruff: noqa: N802 UP006 UP007
2
+ # @omlish-lite
3
+ import logging
4
+
5
+
6
+ class ProxyLogFilterer(logging.Filterer):
7
+ def __init__(self, underlying: logging.Filterer) -> None: # noqa
8
+ self._underlying = underlying
9
+
10
+ @property
11
+ def underlying(self) -> logging.Filterer:
12
+ return self._underlying
13
+
14
+ @property
15
+ def filters(self):
16
+ return self._underlying.filters
17
+
18
+ @filters.setter
19
+ def filters(self, filters):
20
+ self._underlying.filters = filters
21
+
22
+ def addFilter(self, filter): # noqa
23
+ self._underlying.addFilter(filter)
24
+
25
+ def removeFilter(self, filter): # noqa
26
+ self._underlying.removeFilter(filter)
27
+
28
+ def filter(self, record):
29
+ return self._underlying.filter(record)
30
+
31
+
32
+ class ProxyLogHandler(ProxyLogFilterer, logging.Handler):
33
+ def __init__(self, underlying: logging.Handler) -> None: # noqa
34
+ ProxyLogFilterer.__init__(self, underlying)
35
+
36
+ _underlying: logging.Handler
37
+
38
+ @property
39
+ def underlying(self) -> logging.Handler:
40
+ return self._underlying
41
+
42
+ def get_name(self):
43
+ return self._underlying.get_name()
44
+
45
+ def set_name(self, name):
46
+ self._underlying.set_name(name)
47
+
48
+ @property
49
+ def name(self):
50
+ return self._underlying.name
51
+
52
+ @property
53
+ def level(self):
54
+ return self._underlying.level
55
+
56
+ @level.setter
57
+ def level(self, level):
58
+ self._underlying.level = level
59
+
60
+ @property
61
+ def formatter(self):
62
+ return self._underlying.formatter
63
+
64
+ @formatter.setter
65
+ def formatter(self, formatter):
66
+ self._underlying.formatter = formatter
67
+
68
+ def createLock(self):
69
+ self._underlying.createLock()
70
+
71
+ def acquire(self):
72
+ self._underlying.acquire()
73
+
74
+ def release(self):
75
+ self._underlying.release()
76
+
77
+ def setLevel(self, level):
78
+ self._underlying.setLevel(level)
79
+
80
+ def format(self, record):
81
+ return self._underlying.format(record)
82
+
83
+ def emit(self, record):
84
+ self._underlying.emit(record)
85
+
86
+ def handle(self, record):
87
+ return self._underlying.handle(record)
88
+
89
+ def setFormatter(self, fmt):
90
+ self._underlying.setFormatter(fmt)
91
+
92
+ def flush(self):
93
+ self._underlying.flush()
94
+
95
+ def close(self):
96
+ self._underlying.close()
97
+
98
+ def handleError(self, record):
99
+ self._underlying.handleError(record)
@@ -0,0 +1,126 @@
1
+ # ruff: noqa: N802 UP006 UP007
2
+ # @omlish-lite
3
+ """
4
+ TODO:
5
+ - structured
6
+ - prefixed
7
+ - debug
8
+ """
9
+ import contextlib
10
+ import datetime
11
+ import logging
12
+ import typing as ta
13
+
14
+ from .filters import TidLogFilter
15
+ from .json import JsonLogFormatter
16
+ from .proxy import ProxyLogHandler
17
+
18
+
19
+ ##
20
+
21
+
22
+ STANDARD_LOG_FORMAT_PARTS = [
23
+ ('asctime', '%(asctime)-15s'),
24
+ ('process', 'pid=%(process)-6s'),
25
+ ('thread', 'tid=%(thread)x'),
26
+ ('levelname', '%(levelname)s'),
27
+ ('name', '%(name)s'),
28
+ ('separator', '::'),
29
+ ('message', '%(message)s'),
30
+ ]
31
+
32
+
33
+ class StandardLogFormatter(logging.Formatter):
34
+ @staticmethod
35
+ def build_log_format(parts: ta.Iterable[ta.Tuple[str, str]]) -> str:
36
+ return ' '.join(v for k, v in parts)
37
+
38
+ converter = datetime.datetime.fromtimestamp # type: ignore
39
+
40
+ def formatTime(self, record, datefmt=None):
41
+ ct = self.converter(record.created) # type: ignore
42
+ if datefmt:
43
+ return ct.strftime(datefmt) # noqa
44
+ else:
45
+ t = ct.strftime('%Y-%m-%d %H:%M:%S')
46
+ return '%s.%03d' % (t, record.msecs) # noqa
47
+
48
+
49
+ ##
50
+
51
+
52
+ class StandardLogHandler(ProxyLogHandler):
53
+ pass
54
+
55
+
56
+ ##
57
+
58
+
59
+ @contextlib.contextmanager
60
+ def _locking_logging_module_lock() -> ta.Iterator[None]:
61
+ if hasattr(logging, '_acquireLock'):
62
+ logging._acquireLock() # noqa
63
+ try:
64
+ yield
65
+ finally:
66
+ logging._releaseLock() # type: ignore # noqa
67
+
68
+ elif hasattr(logging, '_lock'):
69
+ # https://github.com/python/cpython/commit/74723e11109a320e628898817ab449b3dad9ee96
70
+ with logging._lock: # noqa
71
+ yield
72
+
73
+ else:
74
+ raise Exception("Can't find lock in logging module")
75
+
76
+
77
+ def configure_standard_logging(
78
+ level: ta.Union[int, str] = logging.INFO,
79
+ *,
80
+ json: bool = False,
81
+ target: ta.Optional[logging.Logger] = None,
82
+ force: bool = False,
83
+ handler_factory: ta.Optional[ta.Callable[[], logging.Handler]] = None,
84
+ ) -> ta.Optional[StandardLogHandler]:
85
+ with _locking_logging_module_lock():
86
+ if target is None:
87
+ target = logging.root
88
+
89
+ #
90
+
91
+ if not force:
92
+ if any(isinstance(h, StandardLogHandler) for h in list(target.handlers)):
93
+ return None
94
+
95
+ #
96
+
97
+ if handler_factory is not None:
98
+ handler = handler_factory()
99
+ else:
100
+ handler = logging.StreamHandler()
101
+
102
+ #
103
+
104
+ formatter: logging.Formatter
105
+ if json:
106
+ formatter = JsonLogFormatter()
107
+ else:
108
+ formatter = StandardLogFormatter(StandardLogFormatter.build_log_format(STANDARD_LOG_FORMAT_PARTS))
109
+ handler.setFormatter(formatter)
110
+
111
+ #
112
+
113
+ handler.addFilter(TidLogFilter())
114
+
115
+ #
116
+
117
+ target.addHandler(handler)
118
+
119
+ #
120
+
121
+ if level is not None:
122
+ target.setLevel(level)
123
+
124
+ #
125
+
126
+ return StandardLogHandler(handler)
omlish/logs/utils.py CHANGED
@@ -2,10 +2,10 @@ import functools
2
2
  import logging
3
3
 
4
4
 
5
- log = logging.getLogger(__name__)
5
+ _log = logging.getLogger(__name__)
6
6
 
7
7
 
8
- def error_logging(log=log): # noqa
8
+ def error_logging(log=_log): # noqa
9
9
  def outer(fn):
10
10
  @functools.wraps(fn)
11
11
  def inner(*args, **kwargs):
@@ -9,8 +9,7 @@ import sys
9
9
  import time
10
10
  import typing as ta
11
11
 
12
- from omlish.lite.logs import log
13
- from omlish.lite.runtime import is_debugger_attached
12
+ from .lite.runtime import is_debugger_attached
14
13
 
15
14
 
16
15
  T = ta.TypeVar('T')
@@ -65,8 +64,8 @@ def subprocess_close(
65
64
  ##
66
65
 
67
66
 
68
- class AbstractSubprocesses(abc.ABC): # noqa
69
- DEFAULT_LOGGER: ta.ClassVar[ta.Optional[logging.Logger]] = log
67
+ class BaseSubprocesses(abc.ABC): # noqa
68
+ DEFAULT_LOGGER: ta.ClassVar[ta.Optional[logging.Logger]] = None
70
69
 
71
70
  def __init__(
72
71
  self,
@@ -79,6 +78,9 @@ class AbstractSubprocesses(abc.ABC): # noqa
79
78
  self._log = log if log is not None else self.DEFAULT_LOGGER
80
79
  self._try_exceptions = try_exceptions if try_exceptions is not None else self.DEFAULT_TRY_EXCEPTIONS
81
80
 
81
+ def set_logger(self, log: ta.Optional[logging.Logger]) -> None:
82
+ self._log = log
83
+
82
84
  #
83
85
 
84
86
  def prepare_args(
@@ -190,23 +192,25 @@ class AbstractSubprocesses(abc.ABC): # noqa
190
192
  ##
191
193
 
192
194
 
193
- class Subprocesses(AbstractSubprocesses):
195
+ class AbstractSubprocesses(BaseSubprocesses, abc.ABC):
196
+ @abc.abstractmethod
194
197
  def check_call(
195
198
  self,
196
199
  *cmd: str,
197
200
  stdout: ta.Any = sys.stderr,
198
201
  **kwargs: ta.Any,
199
202
  ) -> None:
200
- with self.prepare_and_wrap(*cmd, stdout=stdout, **kwargs) as (cmd, kwargs): # noqa
201
- subprocess.check_call(cmd, **kwargs)
203
+ raise NotImplementedError
202
204
 
205
+ @abc.abstractmethod
203
206
  def check_output(
204
207
  self,
205
208
  *cmd: str,
206
209
  **kwargs: ta.Any,
207
210
  ) -> bytes:
208
- with self.prepare_and_wrap(*cmd, **kwargs) as (cmd, kwargs): # noqa
209
- return subprocess.check_output(cmd, **kwargs)
211
+ raise NotImplementedError
212
+
213
+ #
210
214
 
211
215
  def check_output_str(
212
216
  self,
@@ -248,4 +252,89 @@ class Subprocesses(AbstractSubprocesses):
248
252
  return ret.decode().strip()
249
253
 
250
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
+
251
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()
@@ -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
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: omlish
3
- Version: 0.0.0.dev156
3
+ Version: 0.0.0.dev158
4
4
  Summary: omlish
5
5
  Author: wrmsr
6
6
  License: BSD-3-Clause
@@ -1,5 +1,5 @@
1
1
  omlish/.manifests.json,sha256=RX24SRc6DCEg77PUVnaXOKCWa5TF_c9RQJdGIf7gl9c,1135
2
- omlish/__about__.py,sha256=pJXW0d9gycr4V9VlmGz-WLKw7S0ffYStbINM8F0lblQ,3409
2
+ omlish/__about__.py,sha256=9u37nmCWRhb45vCJ-X-WiXn0ty_9hzwZdiym8B62R9c,3409
3
3
  omlish/__init__.py,sha256=SsyiITTuK0v74XpKV8dqNaCmjOlan1JZKrHQv5rWKPA,253
4
4
  omlish/c3.py,sha256=ubu7lHwss5V4UznbejAI0qXhXahrU01MysuHOZI9C4U,8116
5
5
  omlish/cached.py,sha256=UI-XTFBwA6YXWJJJeBn-WkwBkfzDjLBBaZf4nIJA9y0,510
@@ -11,6 +11,7 @@ omlish/iterators.py,sha256=GGLC7RIT86uXMjhIIIqnff_Iu5SI_b9rXYywYGFyzmo,7292
11
11
  omlish/libc.py,sha256=8r7Ejyhttk9ruCfBkxNTrlzir5WPbDE2vmY7VPlceMA,15362
12
12
  omlish/multiprocessing.py,sha256=QZT4C7I-uThCAjaEY3xgUYb-5GagUlnE4etN01LDyU4,5186
13
13
  omlish/runmodule.py,sha256=PWvuAaJ9wQQn6bx9ftEL3_d04DyotNn8dR_twm2pgw0,700
14
+ omlish/subprocesses.py,sha256=n6pk0nUaTFHzD_A6duyKNJ4ggncU7uNepfh_T90etHE,8671
14
15
  omlish/sync.py,sha256=QJ79kxmIqDP9SeHDoZAf--DpFIhDQe1jACy8H4N0yZI,2928
15
16
  omlish/term.py,sha256=EVHm3lEEIc9hT4f8BPmzbNUwlqZ8nrRpCwyQMN7LBm0,9313
16
17
  omlish/antlr/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -75,7 +76,7 @@ omlish/antlr/_runtime/xpath/XPathLexer.py,sha256=xFtdr4ZXMZxb2dnB_ggWyhvlQiC7RXQ
75
76
  omlish/antlr/_runtime/xpath/__init__.py,sha256=lMd_BbXYdlDhZQN_q0TKN978XW5G0pq618F0NaLkpFE,71
76
77
  omlish/argparse/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
77
78
  omlish/argparse/all.py,sha256=EfUSf27vFWqa4Q93AycU5YRsrHt-Nx3pU3uNVapb-EE,1054
78
- omlish/argparse/cli.py,sha256=RrFql1bS1Lw3GA1ooLCJDQX4bK_Ci-dDqD5nEkVgHGI,8072
79
+ omlish/argparse/cli.py,sha256=Nd16RNNABOd9UjfLGtJrDOYkIs5uv1BnoqvJdQ2Ipc8,8273
79
80
  omlish/asyncs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
80
81
  omlish/asyncs/all.py,sha256=uUz9ziKh4_QrgmdhKFMgq6j7mFbiZd3LiogguDCQsGI,587
81
82
  omlish/asyncs/anyio.py,sha256=gfpx-D8QGmUfhnQxHEaHXcAP8zSMQjcGw4COFTGNnHI,8021
@@ -89,6 +90,7 @@ omlish/asyncs/asyncio/all.py,sha256=cyfe1tOXxQYmgfyF9X1dwx0LPQ0Gsub3tFFZGjWGMr8,
89
90
  omlish/asyncs/asyncio/asyncio.py,sha256=JfM59QgB3asgEbrps0zoVbNjWD4kL2XdsEkRMEIoFos,971
90
91
  omlish/asyncs/asyncio/channels.py,sha256=ZbmsEmdK1fV96liHdcVpRqA2dAMkXJt4Q3rFAg3YOIw,1074
91
92
  omlish/asyncs/asyncio/streams.py,sha256=Uc9PCWSfBqrK2kdVtfjjQU1eaYTWYmZm8QISDj2xiuw,1004
93
+ omlish/asyncs/asyncio/subprocesses.py,sha256=XlIWwSxpVB7sMVc75-f7dI6r08JkdipNFRWXUKS8zAw,6960
92
94
  omlish/asyncs/asyncio/timeouts.py,sha256=Rj5OU9BIAPcVZZKp74z7SzUXF5xokh4dgsWkUqOy1aE,355
93
95
  omlish/bootstrap/__init__.py,sha256=-Rtsg7uPQNhh1dIT9nqrz96XlqizwoLnWf-FwOEstJI,730
94
96
  omlish/bootstrap/__main__.py,sha256=4jCwsaogp0FrJjJZ85hzF4-WqluPeheHbfeoKynKvNs,194
@@ -97,7 +99,7 @@ omlish/bootstrap/diag.py,sha256=iemH0nQEHEDzyZztvd_ygGGVpRpgn5UG6naxeQTvXp0,5347
97
99
  omlish/bootstrap/harness.py,sha256=VW8YP-yENGyXIuJ8GL_xintArF13nafwpz-iAghPt34,1967
98
100
  omlish/bootstrap/main.py,sha256=yZhOHDDlj4xB5a89dRdT8z58FsqqnpoBg1-tvY2CJe4,5903
99
101
  omlish/bootstrap/marshal.py,sha256=ZxdAeMNd2qXRZ1HUK89HmEhz8tqlS9OduW34QBscKw0,516
100
- omlish/bootstrap/sys.py,sha256=S6HgjfCKYNuC_iW6gIJNVp8-eJ_wm0JTBMyQRZLE6eQ,8758
102
+ omlish/bootstrap/sys.py,sha256=aqMzxZa_lPj78cgz4guYZAkjT6En32e2LptfEo20NIM,8769
101
103
  omlish/collections/__init__.py,sha256=zeUvcAz073ekko37QKya6sElTMfKTuF1bKrdbMtaRpI,2142
102
104
  omlish/collections/abc.py,sha256=sP7BpTVhx6s6C59mTFeosBi4rHOWC6tbFBYbxdZmvh0,2365
103
105
  omlish/collections/coerce.py,sha256=g68ROb_-5HgH-vI8612mU2S0FZ8-wp2ZHK5_Zy_kVC0,7037
@@ -228,10 +230,9 @@ omlish/http/asgi.py,sha256=wXhBZ21bEl32Kv9yBrRwUR_7pHEgVtHP8ZZwbasQ6-4,3307
228
230
  omlish/http/clients.py,sha256=WRtCNIt9Y790xpem69HiXJY9W-vPlpGPKZwpHusa2EE,6280
229
231
  omlish/http/consts.py,sha256=7BJ4D1MdIvqBcepkgCfBFHolgTwbOlqsOEiee_IjxOA,2289
230
232
  omlish/http/cookies.py,sha256=uuOYlHR6e2SC3GM41V0aozK10nef9tYg83Scqpn5-HM,6351
231
- omlish/http/coroserver.py,sha256=IXyCElwsPNEZZsQbdLJ0P-pLHTBv8MbbsBfNmb4XUaQ,18048
232
233
  omlish/http/dates.py,sha256=Otgp8wRxPgNGyzx8LFowu1vC4EKJYARCiAwLFncpfHM,2875
233
234
  omlish/http/encodings.py,sha256=w2WoKajpaZnQH8j-IBvk5ZFL2O2pAU_iBvZnkocaTlw,164
234
- omlish/http/handlers.py,sha256=frDo9gtQY5d8OzW6T42SFmZFViboOPkZcHLGqaC79f0,773
235
+ omlish/http/handlers.py,sha256=yeBBHJmBKvY1C_qdekLxViy_eZSU7WIMvxO-6CSwD5I,789
235
236
  omlish/http/headers.py,sha256=ZMmjrEiYjzo0YTGyK0YsvjdwUazktGqzVVYorY4fd44,5081
236
237
  omlish/http/json.py,sha256=9XwAsl4966Mxrv-1ytyCqhcE6lbBJw-0_tFZzGszgHE,7440
237
238
  omlish/http/jwt.py,sha256=6Rigk1WrJ059DY4jDIKnxjnChWb7aFdermj2AI2DSvk,4346
@@ -241,6 +242,9 @@ omlish/http/sessions.py,sha256=WVRTy2KjehwQiYTPn7r44gZ4Pqg8sDC_9-wiYON0344,4796
241
242
  omlish/http/sse.py,sha256=MDs9RvxQXoQliImcc6qK1ERajEYM7Q1l8xmr-9ceNBc,2315
242
243
  omlish/http/versions.py,sha256=wSiOXPiClVjkVgSU_VmxkoD1SUYGaoPbP0U5Aw-Ufg8,409
243
244
  omlish/http/wsgi.py,sha256=czZsVUX-l2YTlMrUjKN49wRoP4rVpS0qpeBn4O5BoMY,948
245
+ omlish/http/coro/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
246
+ omlish/http/coro/fdio.py,sha256=RMwZ0w-kJAp-2DazFMtWd7yFtjoBqQVCfHuibQkVlkA,4011
247
+ omlish/http/coro/server.py,sha256=6MjeYygaE4tcq2b8xBIkbNM_e1heDdq98yAwYGFEKdY,18060
244
248
  omlish/inject/__init__.py,sha256=n0RC9UDGsBQQ39cST39-XJqJPq2M0tnnh9yJubW9azo,1891
245
249
  omlish/inject/binder.py,sha256=DAbc8TZi5w8Mna0TUtq0mT4jeDVA7i7SlBtOFrh2swc,4185
246
250
  omlish/inject/bindings.py,sha256=pLXn2U3kvmAS-68IOG-tr77DbiI-wp9hGyy4lhG6_H8,525
@@ -289,7 +293,6 @@ omlish/io/compress/snappy.py,sha256=kCPgZ7PTBAxAnmYzpQCq4HKUIJ4APeAEXsU3Vg2CaDU,
289
293
  omlish/io/compress/zlib.py,sha256=MtnVGfzDlRU1LPl2J8Sa3wwgqnTVBx2uclZygWpH9xI,2115
290
294
  omlish/io/compress/zstd.py,sha256=LrYWVHzk-TqWJA_Bnci2i8QOtrqnFFpppLQhLqanDWM,668
291
295
  omlish/io/fdio/__init__.py,sha256=Y3l4WY4JRi2uLG6kgbGp93fuGfkxkKwZDvhsa0Rwgtk,15
292
- omlish/io/fdio/corohttp.py,sha256=AdsGyaTT4c0V4eUyhxob8Zm4Ixj936DfpwyyJO2-R8k,3995
293
296
  omlish/io/fdio/handlers.py,sha256=OOQhiazbhNMwxLwyzf8KUQrBQSuHIm-UqAMpXmmHGFQ,1344
294
297
  omlish/io/fdio/kqueue.py,sha256=YgGBQibkAUYODYDiGl7Enjtx1oQsJXuDsBLBXgqlLQw,3832
295
298
  omlish/io/fdio/manager.py,sha256=q4wWf7nKrNtjx6yPEvrVnFt4UtK_BTvVlquEGw7poEo,1250
@@ -333,13 +336,13 @@ omlish/lifecycles/manager.py,sha256=Au66KaO-fI-SEJALaPUJsCHYW2GE20xextk1wKn2BEU,
333
336
  omlish/lifecycles/states.py,sha256=zqMOU2ZU-MDNnWuwauM3_anIAiXM8LoBDElDEraptFg,1292
334
337
  omlish/lifecycles/transitions.py,sha256=qQtFby-h4VzbvgaUqT2NnbNumlcOx9FVVADP9t83xj4,1939
335
338
  omlish/lite/__init__.py,sha256=Y3l4WY4JRi2uLG6kgbGp93fuGfkxkKwZDvhsa0Rwgtk,15
336
- omlish/lite/cached.py,sha256=hBW77-F7ZLtFqbLwVrlqaJ4-iFHMQleMWZXaZN1IubA,1308
339
+ omlish/lite/cached.py,sha256=O7ozcoDNFm1Hg2wtpHEqYSp_i_nCLNOP6Ueq_Uk-7mU,1300
337
340
  omlish/lite/check.py,sha256=KvcO86LqWlh2j4ORaZXRR4FM8fFb7kUkNqq3lTs0Ta0,12821
338
341
  omlish/lite/contextmanagers.py,sha256=m9JO--p7L7mSl4cycXysH-1AO27weDKjP3DZG61cwwM,1683
339
342
  omlish/lite/inject.py,sha256=729Qi0TLbQgBtkvx97q1EUMe73VFYA1hu4woXkOTcwM,23572
340
343
  omlish/lite/json.py,sha256=7-02Ny4fq-6YAu5ynvqoijhuYXWpLmfCI19GUeZnb1c,740
341
- omlish/lite/logs.py,sha256=1pcGu0ekhVCcLUckLSP16VccnAoprjtl5Vkdfm7y1Wg,6184
342
- omlish/lite/marshal.py,sha256=jbdKjTeumReSKUNNEn-oAyd5Bdy6NK_9_LsPSHpvqRU,13817
344
+ omlish/lite/logs.py,sha256=CWFG0NKGhqNeEgryF5atN2gkPYbUdTINEw_s1phbINM,51
345
+ omlish/lite/marshal.py,sha256=u5n43bEbct1ps8oIR7wjFCSWeyOhfHAF7LxUjELh8Jk,13830
343
346
  omlish/lite/maybes.py,sha256=7OlHJ8Q2r4wQ-aRbZSlJY7x0e8gDvufFdlohGEIJ3P4,833
344
347
  omlish/lite/pycharm.py,sha256=pUOJevrPClSqTCEOkQBO11LKX2003tfDcp18a03QFrc,1163
345
348
  omlish/lite/reflect.py,sha256=ad_ya_zZJOQB8HoNjs9yc66R54zgflwJVPJqiBXMzqA,1681
@@ -349,17 +352,19 @@ omlish/lite/secrets.py,sha256=3Mz3V2jf__XU9qNHcH56sBSw95L3U2UPL24bjvobG0c,816
349
352
  omlish/lite/socket.py,sha256=7OYgkXTcQv0wq7TQuLnl9y6dJA1ZT6Vbc1JH59QlxgY,1792
350
353
  omlish/lite/socketserver.py,sha256=doTXIctu_6c8XneFtzPFVG_Wq6xVmA3p9ymut8IvBoU,1586
351
354
  omlish/lite/strings.py,sha256=QURcE4-1pKVW8eT_5VCJpXaHDWR2dW2pYOChTJnZDiQ,1504
352
- omlish/lite/subprocesses.py,sha256=fN8Hu1cDhu9PoYlfwYyIsMpeznOzisIU_3eKcYcnARs,6700
353
355
  omlish/lite/typing.py,sha256=U3-JaEnkDSYxK4tsu_MzUn3RP6qALBe5FXQXpD-licE,1090
354
- omlish/lite/asyncio/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
355
- omlish/lite/asyncio/subprocesses.py,sha256=pTcSbBDM6rpPKnjl8YqfdOhThDSalDcZHuvaCzYF07o,7729
356
- omlish/logs/__init__.py,sha256=FbOyAW-lGH8gyBlSVArwljdYAU6RnwZLI5LwAfuNnrk,438
356
+ omlish/logs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
357
357
  omlish/logs/abc.py,sha256=ho4ABKYMKX-V7g4sp1BByuOLzslYzLlQ0MESmjEpT-o,8005
358
- omlish/logs/configs.py,sha256=EE0jlNaXJbGnM7V-y4xS5VwyTBSTzFzc0BYaVjg0JmA,1283
359
- omlish/logs/formatters.py,sha256=q79nMnR2mRIStPyGrydQHpYTXgC5HHptt8lH3W2Wwbs,671
360
- omlish/logs/handlers.py,sha256=UpzUf3kWBBzWOnrtljoZsLjISw3Ix-ePz3Nsmp6lRgE,255
358
+ omlish/logs/all.py,sha256=9WiEBD1_FAie8b89zq7zmy8lav2eIJUIA3SpdkXsaMQ,546
359
+ omlish/logs/color.py,sha256=02feYPZm4A7qHeBABpiar2J2E6tf-vtw1pOQAsJs_1c,668
360
+ omlish/logs/configs.py,sha256=XOc8rWxfPpPMxJESVD2mLCUoLtbQnGnZwvYhhqe7DD8,772
361
+ omlish/logs/filters.py,sha256=2noFRyBez3y519fpfsDSt1vo8wX-85b8sMXZi5o_xyE,208
362
+ omlish/logs/handlers.py,sha256=zgSnKQA5q9Fu7T0Nkd7twog9H1Wg9-bDCzz4_F1TOBo,319
363
+ omlish/logs/json.py,sha256=zyqMWpZY3lk4WRk4wgmataBomGX9S3iDsydiM1sS-lI,1366
361
364
  omlish/logs/noisy.py,sha256=Ubc-eTH6ZbGYsLfUUi69JAotwuUwzb-SJBeGo_0dIZI,348
362
- omlish/logs/utils.py,sha256=MgGovbP0zUrZ3FGD3qYNQWn-l0jy0Y0bStcQvv5BOmQ,391
365
+ omlish/logs/proxy.py,sha256=A-ROPUUAlF397qTbEqhel6YhQMstNuXL3Xmts7w9dAo,2347
366
+ omlish/logs/standard.py,sha256=FO2pK-jXW55LkjX6OZZj1keKOYeZfq8SbpHodubgSRo,2903
367
+ omlish/logs/utils.py,sha256=mzHrZ9ji75p5A8qR29eUr05CBAHMb8J753MSkID_VaQ,393
363
368
  omlish/manifests/__init__.py,sha256=P2B0dpT8D7l5lJwRGPA92IcQj6oeXfd90X5-q9BJrKg,51
364
369
  omlish/manifests/load.py,sha256=8R-S5CyQpAbxDHt5wcNF6mAYri8bGndn6R2uEVOh52Y,4809
365
370
  omlish/manifests/types.py,sha256=d8bv5tknCJqclRfxCpao_8XxHo2yofhLpVHQTB-MfNw,260
@@ -505,7 +510,7 @@ omlish/testing/pytest/plugins/__init__.py,sha256=ys1zXrYrNm7Uo6YOIVJ6Bd3dQo6kv38
505
510
  omlish/testing/pytest/plugins/_registry.py,sha256=IK04KlBgiOJxKAyCCgjpX2R-9tE-btalYJkgjLc8Te8,77
506
511
  omlish/testing/pytest/plugins/asyncs.py,sha256=CG-cWWxCtxVIyKJKEjxfFV0MVwYBHPo1mb-umCGz9X8,5532
507
512
  omlish/testing/pytest/plugins/depskip.py,sha256=xithY-OMtjwhv8mcRNkv-WI_PSQtHldQ8H1s60MIXkk,2673
508
- omlish/testing/pytest/plugins/logging.py,sha256=1zs6Xe54wiaSjabCviaFXwKkoN97CKm3mA5mEoUeJGs,380
513
+ omlish/testing/pytest/plugins/logging.py,sha256=Y1I_3DiiuDSynObkm8bNPZxdvljUWXbqD6YUM5uI34o,391
509
514
  omlish/testing/pytest/plugins/managermarks.py,sha256=AP3ty-QB-8O5DkulwUOudBlUOvXMHhBfNyY-0yCmejk,1520
510
515
  omlish/testing/pytest/plugins/pydevd.py,sha256=AXtN83M39ZKJ4VH3MJEhvPnAmYzD5u1r8ehz-0om50Q,842
511
516
  omlish/testing/pytest/plugins/repeat.py,sha256=flSQzE9GFOWksVKz-mUGnpxJpv3yRqn1G4K8pW7JHs0,498
@@ -520,9 +525,9 @@ omlish/text/glyphsplit.py,sha256=Ug-dPRO7x-OrNNr8g1y6DotSZ2KH0S-VcOmUobwa4B0,329
520
525
  omlish/text/indent.py,sha256=6Jj6TFY9unaPa4xPzrnZemJ-fHsV53IamP93XGjSUHs,1274
521
526
  omlish/text/parts.py,sha256=7vPF1aTZdvLVYJ4EwBZVzRSy8XB3YqPd7JwEnNGGAOo,6495
522
527
  omlish/text/random.py,sha256=jNWpqiaKjKyTdMXC-pWAsSC10AAP-cmRRPVhm59ZWLk,194
523
- omlish-0.0.0.dev156.dist-info/LICENSE,sha256=B_hVtavaA8zCYDW99DYdcpDLKz1n3BBRjZrcbv8uG8c,1451
524
- omlish-0.0.0.dev156.dist-info/METADATA,sha256=_LbGRk-hTyGZJFGz-n_Jjjr65O9YGLkRqiLcCMEPLyE,4264
525
- omlish-0.0.0.dev156.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
526
- omlish-0.0.0.dev156.dist-info/entry_points.txt,sha256=Lt84WvRZJskWCAS7xnQGZIeVWksprtUHj0llrvVmod8,35
527
- omlish-0.0.0.dev156.dist-info/top_level.txt,sha256=pePsKdLu7DvtUiecdYXJ78iO80uDNmBlqe-8hOzOmfs,7
528
- omlish-0.0.0.dev156.dist-info/RECORD,,
528
+ omlish-0.0.0.dev158.dist-info/LICENSE,sha256=B_hVtavaA8zCYDW99DYdcpDLKz1n3BBRjZrcbv8uG8c,1451
529
+ omlish-0.0.0.dev158.dist-info/METADATA,sha256=Xdok31SNsavtWgVVYt_kPTdjncdziI2ByRjAj1QQJRs,4264
530
+ omlish-0.0.0.dev158.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
531
+ omlish-0.0.0.dev158.dist-info/entry_points.txt,sha256=Lt84WvRZJskWCAS7xnQGZIeVWksprtUHj0llrvVmod8,35
532
+ omlish-0.0.0.dev158.dist-info/top_level.txt,sha256=pePsKdLu7DvtUiecdYXJ78iO80uDNmBlqe-8hOzOmfs,7
533
+ omlish-0.0.0.dev158.dist-info/RECORD,,
File without changes