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 +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
|