omlish 0.0.0.dev156__py3-none-any.whl → 0.0.0.dev158__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
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