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 +2 -2
- omlish/argparse/cli.py +4 -0
- omlish/{lite → asyncs}/asyncio/subprocesses.py +19 -54
- omlish/bootstrap/sys.py +1 -1
- omlish/{io/fdio/corohttp.py → http/coro/fdio.py} +6 -5
- omlish/http/{coroserver.py → coro/server.py} +12 -12
- omlish/http/handlers.py +1 -1
- omlish/lite/cached.py +2 -2
- omlish/lite/logs.py +0 -270
- omlish/lite/marshal.py +1 -0
- omlish/logs/__init__.py +0 -32
- omlish/logs/all.py +37 -0
- omlish/logs/{formatters.py → color.py} +1 -2
- omlish/logs/configs.py +7 -38
- omlish/logs/filters.py +10 -0
- omlish/logs/handlers.py +4 -1
- omlish/logs/json.py +56 -0
- omlish/logs/proxy.py +99 -0
- omlish/logs/standard.py +126 -0
- omlish/logs/utils.py +2 -2
- omlish/{lite/subprocesses.py → subprocesses.py} +98 -9
- omlish/testing/pytest/plugins/logging.py +1 -1
- {omlish-0.0.0.dev156.dist-info → omlish-0.0.0.dev158.dist-info}/METADATA +1 -1
- {omlish-0.0.0.dev156.dist-info → omlish-0.0.0.dev158.dist-info}/RECORD +29 -24
- /omlish/{lite/asyncio → http/coro}/__init__.py +0 -0
- {omlish-0.0.0.dev156.dist-info → omlish-0.0.0.dev158.dist-info}/LICENSE +0 -0
- {omlish-0.0.0.dev156.dist-info → omlish-0.0.0.dev158.dist-info}/WHEEL +0 -0
- {omlish-0.0.0.dev156.dist-info → omlish-0.0.0.dev158.dist-info}/entry_points.txt +0 -0
- {omlish-0.0.0.dev156.dist-info → omlish-0.0.0.dev158.dist-info}/top_level.txt +0 -0
omlish/__about__.py
CHANGED
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 ...
|
12
|
-
from
|
13
|
-
from
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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(
|
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
@@ -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 ...
|
6
|
-
from ...
|
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 ..
|
10
|
-
from
|
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
|
67
|
-
from
|
68
|
-
from
|
69
|
-
from
|
70
|
-
from
|
71
|
-
from
|
72
|
-
from
|
73
|
-
from
|
74
|
-
from
|
75
|
-
from
|
76
|
-
from
|
77
|
-
from
|
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
|
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
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
|
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
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:
|
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)
|
omlish/logs/standard.py
ADDED
@@ -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
|
-
|
5
|
+
_log = logging.getLogger(__name__)
|
6
6
|
|
7
7
|
|
8
|
-
def error_logging(log=
|
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
|
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
|
69
|
-
DEFAULT_LOGGER: ta.ClassVar[ta.Optional[logging.Logger]] =
|
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
|
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
|
-
|
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
|
-
|
209
|
-
|
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,5 +1,5 @@
|
|
1
1
|
omlish/.manifests.json,sha256=RX24SRc6DCEg77PUVnaXOKCWa5TF_c9RQJdGIf7gl9c,1135
|
2
|
-
omlish/__about__.py,sha256=
|
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=
|
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=
|
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=
|
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=
|
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=
|
342
|
-
omlish/lite/marshal.py,sha256=
|
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/
|
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/
|
359
|
-
omlish/logs/
|
360
|
-
omlish/logs/
|
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/
|
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=
|
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.
|
524
|
-
omlish-0.0.0.
|
525
|
-
omlish-0.0.0.
|
526
|
-
omlish-0.0.0.
|
527
|
-
omlish-0.0.0.
|
528
|
-
omlish-0.0.0.
|
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
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|