omlish 0.0.0.dev217__py3-none-any.whl → 0.0.0.dev219__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/sockets/io.py ADDED
@@ -0,0 +1,69 @@
1
+ # ruff: noqa: UP006 UP007
2
+ # @omlish-lite
3
+ import io
4
+ import socket
5
+ import typing as ta
6
+
7
+
8
+ ##
9
+
10
+
11
+ class SocketWriter(io.BufferedIOBase):
12
+ """
13
+ Simple writable BufferedIOBase implementation for a socket
14
+
15
+ Does not hold data in a buffer, avoiding any need to call flush().
16
+ """
17
+
18
+ def __init__(self, sock):
19
+ super().__init__()
20
+
21
+ self._sock = sock
22
+
23
+ def writable(self):
24
+ return True
25
+
26
+ def write(self, b):
27
+ self._sock.sendall(b)
28
+ with memoryview(b) as view:
29
+ return view.nbytes
30
+
31
+ def fileno(self):
32
+ return self._sock.fileno()
33
+
34
+
35
+ class SocketIoPair(ta.NamedTuple):
36
+ r: ta.BinaryIO
37
+ w: ta.BinaryIO
38
+
39
+ @classmethod
40
+ def from_socket(
41
+ cls,
42
+ sock: socket.socket,
43
+ *,
44
+ r_buf_size: int = -1,
45
+ w_buf_size: int = 0,
46
+ ) -> 'SocketIoPair':
47
+ rf: ta.Any = sock.makefile('rb', r_buf_size)
48
+
49
+ if w_buf_size:
50
+ wf: ta.Any = SocketWriter(sock)
51
+ else:
52
+ wf = sock.makefile('wb', w_buf_size)
53
+
54
+ return cls(rf, wf)
55
+
56
+
57
+ ##
58
+
59
+
60
+ def close_socket_immediately(sock: socket.socket) -> None:
61
+ try:
62
+ # Explicitly shutdown. socket.close() merely releases the socket and waits for GC to perform the actual close.
63
+ sock.shutdown(socket.SHUT_WR)
64
+
65
+ except OSError:
66
+ # Some platforms may raise ENOTCONN here
67
+ pass
68
+
69
+ sock.close()
File without changes
@@ -0,0 +1,134 @@
1
+ # ruff: noqa: UP006 UP007
2
+ # @omlish-lite
3
+ import abc
4
+ import concurrent.futures as cf
5
+ import dataclasses as dc
6
+ import socket
7
+ import typing as ta
8
+
9
+ from ..addresses import SocketAndAddress
10
+ from ..handlers import SocketHandler
11
+ from ..io import SocketIoPair
12
+ from ..io import close_socket_immediately
13
+
14
+
15
+ SocketServerHandler = ta.Callable[[SocketAndAddress], None] # ta.TypeAlias
16
+
17
+
18
+ ##
19
+
20
+
21
+ class SocketServerHandler_(abc.ABC): # noqa
22
+ @abc.abstractmethod
23
+ def __call__(self, conn: SocketAndAddress) -> None:
24
+ raise NotImplementedError
25
+
26
+
27
+ ##
28
+
29
+
30
+ @dc.dataclass(frozen=True)
31
+ class StandardSocketServerHandler(SocketServerHandler_):
32
+ handler: SocketServerHandler
33
+
34
+ timeout: ta.Optional[float] = None
35
+
36
+ # http://bugs.python.org/issue6192
37
+ # TODO: https://eklitzke.org/the-caveats-of-tcp-nodelay
38
+ disable_nagle_algorithm: bool = False
39
+
40
+ no_close: bool = False
41
+
42
+ def __call__(self, conn: SocketAndAddress) -> None:
43
+ try:
44
+ if self.timeout is not None:
45
+ conn.socket.settimeout(self.timeout)
46
+
47
+ if self.disable_nagle_algorithm:
48
+ conn.socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, True)
49
+
50
+ self.handler(conn)
51
+
52
+ finally:
53
+ close_socket_immediately(conn.socket)
54
+
55
+
56
+ #
57
+
58
+
59
+ @dc.dataclass(frozen=True)
60
+ class CallbackWrappedSocketServerHandler(SocketServerHandler_):
61
+ handler: SocketServerHandler
62
+
63
+ before_handle: ta.Optional[SocketServerHandler] = None
64
+ after_handle: ta.Optional[SocketServerHandler] = None
65
+
66
+ # Return True if suppress like __exit__
67
+ on_error: ta.Optional[ta.Callable[[SocketAndAddress, Exception], bool]] = None
68
+
69
+ finally_: ta.Optional[SocketServerHandler] = None
70
+
71
+ def __call__(self, conn: SocketAndAddress) -> None:
72
+ try:
73
+ if (before_handle := self.before_handle) is not None:
74
+ before_handle(conn)
75
+
76
+ self.handler(conn)
77
+
78
+ except Exception as e:
79
+ if (on_error := self.on_error) is not None and on_error(conn, e):
80
+ pass
81
+ else:
82
+ raise
83
+
84
+ else:
85
+ if (after_handle := self.after_handle) is not None:
86
+ after_handle(conn)
87
+
88
+ finally:
89
+ if (finally_ := self.finally_) is not None:
90
+ finally_(conn)
91
+
92
+
93
+ #
94
+
95
+
96
+ @dc.dataclass(frozen=True)
97
+ class SocketHandlerSocketServerHandler(SocketServerHandler_):
98
+ handler: SocketHandler
99
+
100
+ r_buf_size: int = -1
101
+ w_buf_size: int = 0
102
+
103
+ def __call__(self, conn: SocketAndAddress) -> None:
104
+ fp = SocketIoPair.from_socket(
105
+ conn.socket,
106
+ r_buf_size=self.r_buf_size,
107
+ w_buf_size=self.w_buf_size,
108
+ )
109
+
110
+ self.handler(conn.address, fp)
111
+
112
+
113
+ #
114
+
115
+
116
+ @dc.dataclass(frozen=True)
117
+ class SocketWrappingSocketServerHandler(SocketServerHandler_):
118
+ handler: SocketServerHandler
119
+ wrapper: ta.Callable[[SocketAndAddress], SocketAndAddress]
120
+
121
+ def __call__(self, conn: SocketAndAddress) -> None:
122
+ wrapped_conn = self.wrapper(conn)
123
+ self.handler(wrapped_conn)
124
+
125
+
126
+ #
127
+
128
+ @dc.dataclass(frozen=True)
129
+ class ExecutorSocketServerHandler(SocketServerHandler_):
130
+ handler: SocketServerHandler
131
+ executor: cf.Executor
132
+
133
+ def __call__(self, conn: SocketAndAddress) -> None:
134
+ self.executor.submit(self.handler, conn)
@@ -0,0 +1,152 @@
1
+ # @omlish-lite
2
+ # ruff: noqa: UP006 UP007
3
+ import abc
4
+ import contextlib
5
+ import selectors
6
+ import threading
7
+ import typing as ta
8
+
9
+ from ..bind import SocketBinder
10
+ from ..io import close_socket_immediately
11
+ from .handlers import SocketServerHandler
12
+
13
+
14
+ ##
15
+
16
+
17
+ class SocketServer(abc.ABC):
18
+ def __init__(
19
+ self,
20
+ binder: SocketBinder,
21
+ handler: SocketServerHandler,
22
+ *,
23
+ on_error: ta.Optional[ta.Callable[[BaseException], None]] = None,
24
+ poll_interval: float = .5,
25
+ shutdown_timeout: ta.Optional[float] = None,
26
+ ) -> None:
27
+ super().__init__()
28
+
29
+ self._binder = binder
30
+ self._handler = handler
31
+ self._on_error = on_error
32
+ self._poll_interval = poll_interval
33
+ self._shutdown_timeout = shutdown_timeout
34
+
35
+ self._lock = threading.RLock()
36
+ self._is_shutdown = threading.Event()
37
+ self._should_shutdown = False
38
+
39
+ @property
40
+ def binder(self) -> SocketBinder:
41
+ return self._binder
42
+
43
+ @property
44
+ def handler(self) -> SocketServerHandler:
45
+ return self._handler
46
+
47
+ #
48
+
49
+ class SelectorProtocol(ta.Protocol):
50
+ def register(self, *args, **kwargs) -> None:
51
+ raise NotImplementedError
52
+
53
+ def select(self, *args, **kwargs) -> bool:
54
+ raise NotImplementedError
55
+
56
+ Selector: ta.ClassVar[ta.Any]
57
+ if hasattr(selectors, 'PollSelector'):
58
+ Selector = selectors.PollSelector
59
+ else:
60
+ Selector = selectors.SelectSelector
61
+
62
+ #
63
+
64
+ @contextlib.contextmanager
65
+ def _listen_context(self) -> ta.Iterator[SelectorProtocol]:
66
+ with contextlib.ExitStack() as es:
67
+ es.enter_context(self._lock)
68
+ es.enter_context(self._binder)
69
+
70
+ self._binder.listen()
71
+
72
+ self._is_shutdown.clear()
73
+ try:
74
+ # XXX: Consider using another file descriptor or connecting to the socket to wake this up instead of
75
+ # polling. Polling reduces our responsiveness to a shutdown request and wastes cpu at all other times.
76
+ with self.Selector() as selector:
77
+ selector.register(self._binder.fileno(), selectors.EVENT_READ)
78
+
79
+ yield selector
80
+
81
+ finally:
82
+ self._is_shutdown.set()
83
+
84
+ @contextlib.contextmanager
85
+ def loop_context(self, poll_interval: ta.Optional[float] = None) -> ta.Iterator[ta.Iterator[bool]]:
86
+ if poll_interval is None:
87
+ poll_interval = self._poll_interval
88
+
89
+ with self._listen_context() as selector:
90
+ def loop():
91
+ while not self._should_shutdown:
92
+ ready = selector.select(poll_interval)
93
+
94
+ # bpo-35017: shutdown() called during select(), exit immediately.
95
+ if self._should_shutdown:
96
+ break # type: ignore[unreachable]
97
+
98
+ if ready:
99
+ try:
100
+ conn = self._binder.accept()
101
+
102
+ except OSError as exc:
103
+ if (on_error := self._on_error) is not None:
104
+ on_error(exc)
105
+
106
+ return
107
+
108
+ try:
109
+ self._handler(conn)
110
+
111
+ except Exception as exc: # noqa
112
+ if (on_error := self._on_error) is not None:
113
+ on_error(exc)
114
+
115
+ close_socket_immediately(conn.socket)
116
+
117
+ yield bool(ready)
118
+
119
+ yield loop()
120
+
121
+ def run(self, poll_interval: ta.Optional[float] = None) -> None:
122
+ with self.loop_context(poll_interval=poll_interval) as loop:
123
+ for _ in loop:
124
+ pass
125
+
126
+ #
127
+
128
+ class _NOT_SET: # noqa
129
+ def __new__(cls, *args, **kwargs): # noqa
130
+ raise TypeError
131
+
132
+ def shutdown(
133
+ self,
134
+ block: bool = False,
135
+ timeout: ta.Union[float, None, ta.Type[_NOT_SET]] = _NOT_SET,
136
+ ) -> None:
137
+ self._should_shutdown = True
138
+
139
+ if block:
140
+ if timeout is self._NOT_SET:
141
+ timeout = self._shutdown_timeout
142
+
143
+ if not self._is_shutdown.wait(timeout=timeout): # type: ignore
144
+ raise TimeoutError
145
+
146
+ #
147
+
148
+ def __enter__(self) -> 'SocketServer':
149
+ return self
150
+
151
+ def __exit__(self, exc_type, exc_val, exc_tb):
152
+ self.shutdown()
@@ -0,0 +1,123 @@
1
+ # @omlish-lite
2
+ # ruff: noqa: UP006 UP007
3
+ import threading
4
+ import time
5
+ import typing as ta
6
+
7
+ from ...lite.check import check
8
+ from ..addresses import SocketAndAddress
9
+ from .handlers import SocketServerHandler
10
+
11
+
12
+ ##
13
+
14
+
15
+ class ThreadingSocketServerHandler:
16
+ def __init__(
17
+ self,
18
+ handler: SocketServerHandler,
19
+ *,
20
+ shutdown_timeout: ta.Optional[float] = None,
21
+ ) -> None:
22
+ super().__init__()
23
+
24
+ self._handler = handler
25
+ self._shutdown_timeout = shutdown_timeout
26
+
27
+ self._lock = threading.RLock()
28
+ self._threads: ta.List[threading.Thread] = []
29
+ self._is_shutdown = False
30
+
31
+ @property
32
+ def handler(self) -> SocketServerHandler:
33
+ return self._handler
34
+
35
+ #
36
+
37
+ def __call__(self, conn: SocketAndAddress) -> None:
38
+ self.handle(conn)
39
+
40
+ def handle(self, conn: SocketAndAddress) -> None:
41
+ with self._lock:
42
+ check.state(not self._is_shutdown)
43
+
44
+ self._reap()
45
+
46
+ t = threading.Thread(
47
+ target=self._handler,
48
+ args=(conn,),
49
+ )
50
+
51
+ self._threads.append(t)
52
+
53
+ t.start()
54
+
55
+ #
56
+
57
+ def _reap(self) -> None:
58
+ with self._lock:
59
+ self._threads[:] = (thread for thread in self._threads if thread.is_alive())
60
+
61
+ def is_alive(self) -> bool:
62
+ with self._lock:
63
+ self._reap()
64
+
65
+ return bool(self._threads)
66
+
67
+ def join(self, timeout: ta.Optional[float] = None) -> None:
68
+ if timeout is not None:
69
+ deadline: ta.Optional[float] = time.time() + timeout
70
+ else:
71
+ deadline = None
72
+
73
+ def calc_timeout() -> ta.Optional[float]:
74
+ if deadline is None:
75
+ return None
76
+
77
+ tt = deadline - time.time()
78
+ if tt <= 0:
79
+ raise TimeoutError
80
+
81
+ return tt
82
+
83
+ if not (self._lock.acquire(timeout=calc_timeout() or -1)):
84
+ raise TimeoutError
85
+
86
+ try:
87
+ self._reap()
88
+
89
+ for t in self._threads:
90
+ t.join(timeout=calc_timeout())
91
+
92
+ if t.is_alive():
93
+ raise TimeoutError
94
+
95
+ finally:
96
+ self._lock.release()
97
+
98
+ #
99
+
100
+ class _NOT_SET: # noqa
101
+ def __new__(cls, *args, **kwargs): # noqa
102
+ raise TypeError
103
+
104
+ def shutdown(
105
+ self,
106
+ block: bool = False,
107
+ timeout: ta.Union[float, None, ta.Type[_NOT_SET]] = _NOT_SET,
108
+ ) -> None:
109
+ self._is_shutdown = True
110
+
111
+ if block:
112
+ if timeout is self._NOT_SET:
113
+ timeout = self._shutdown_timeout
114
+
115
+ self.join(timeout=timeout) # type: ignore
116
+
117
+ #
118
+
119
+ def __enter__(self) -> 'ThreadingSocketServerHandler':
120
+ return self
121
+
122
+ def __exit__(self, exc_type, exc_val, exc_tb):
123
+ self.shutdown()
@@ -2,7 +2,7 @@
2
2
  TODO:
3
3
  - sync/async...
4
4
  """
5
- from ... import secrets as sec
5
+ from ..secrets import all as sec
6
6
 
7
7
 
8
8
  class SqlFunctionSecrets(sec.Secrets):
omlish/sql/dbs.py CHANGED
@@ -3,7 +3,7 @@ import urllib.parse
3
3
 
4
4
  from .. import dataclasses as dc
5
5
  from .. import lang
6
- from .. import secrets as sec
6
+ from ..secrets import all as sec
7
7
 
8
8
 
9
9
  ##
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: omlish
3
- Version: 0.0.0.dev217
3
+ Version: 0.0.0.dev219
4
4
  Summary: omlish
5
5
  Author: wrmsr
6
6
  License: BSD-3-Clause
@@ -18,7 +18,7 @@ Requires-Dist: sniffio~=1.3; extra == "all"
18
18
  Requires-Dist: greenlet~=3.1; extra == "all"
19
19
  Requires-Dist: trio~=0.27; extra == "all"
20
20
  Requires-Dist: trio-asyncio~=0.15; extra == "all"
21
- Requires-Dist: lz4~=4.3; extra == "all"
21
+ Requires-Dist: lz4~=4.4; extra == "all"
22
22
  Requires-Dist: python-snappy~=0.7; extra == "all"
23
23
  Requires-Dist: zstandard~=0.23; extra == "all"
24
24
  Requires-Dist: brotli~=1.1; extra == "all"
@@ -57,7 +57,7 @@ Requires-Dist: greenlet~=3.1; extra == "async"
57
57
  Requires-Dist: trio~=0.27; extra == "async"
58
58
  Requires-Dist: trio-asyncio~=0.15; extra == "async"
59
59
  Provides-Extra: compress
60
- Requires-Dist: lz4~=4.3; extra == "compress"
60
+ Requires-Dist: lz4~=4.4; extra == "compress"
61
61
  Requires-Dist: python-snappy~=0.7; extra == "compress"
62
62
  Requires-Dist: zstandard~=0.23; extra == "compress"
63
63
  Requires-Dist: brotli~=1.1; extra == "compress"
@@ -1,5 +1,5 @@
1
1
  omlish/.manifests.json,sha256=YGmAnUBszmosQQ_7Hh2wwtDiYdYZ4unNKYzOtALuels,7968
2
- omlish/__about__.py,sha256=kDIujbwF1DOvbfOg4BotM1Kd9bV-L3rLG99gQZvd-EU,3380
2
+ omlish/__about__.py,sha256=XK2FqqJrrqiv22AiJ0Zjsv-tVj5fAtCQ0g6QGY3-xtU,3380
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
@@ -224,9 +224,11 @@ omlish/docker/consts.py,sha256=wvwfUtEFrEWZKfREWqSMrx8xjjl8P5MNUSF6qzzgJHY,70
224
224
  omlish/docker/detect.py,sha256=Qrdbosm2wJkxKDuy8gaGmbQoxk4Wnp1HJjAEz58NA8Y,614
225
225
  omlish/docker/hub.py,sha256=7LIuJGdA-N1Y1dmo50ynKM1KUTcnQM_5XbtPbdT_QLU,3940
226
226
  omlish/docker/manifests.py,sha256=LR4FpOGNUT3bZQ-gTjB6r_-1C3YiG30QvevZjrsVUQM,7068
227
- omlish/docker/oci.py,sha256=wbiOpZQWZtiCtyoDpZhYyHvwkZv5przil9DRLAvHrfs,2743
228
227
  omlish/docker/portrelay.py,sha256=QlRoTnQXs5INguR7XOj1xH0gNdL9SUeZm5z45DUctXo,1222
229
228
  omlish/docker/timebomb.py,sha256=A_pgIDaXKsQwPiikrCTgIJl91gwYqkPGFY6j-Naq07Q,342
229
+ omlish/docker/oci/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
230
+ omlish/docker/oci/data.py,sha256=4KtSxziT70BhF30ozQ1SCfX4y0LT_5x0CuOKC4zrEV4,2616
231
+ omlish/docker/oci/media.py,sha256=fJ8VcU-edDpg-FyJQamw-sUlhTghkC-WQ1TC4MiRpFU,4499
230
232
  omlish/formats/__init__.py,sha256=T0AG1gFnqQ5JiHN0UPQjQ-7g5tnxMIG-mgOvMYExYAM,21
231
233
  omlish/formats/cbor.py,sha256=o_Hbe4kthO9CeXK-FySrw0dHVlrdyTo2Y8PpGRDfZ3c,514
232
234
  omlish/formats/cloudpickle.py,sha256=16si4yUp_pAdDWGECAWf6HLA2PwSANGGgDoMLGZUem8,579
@@ -262,7 +264,7 @@ omlish/formats/json/stream/errors.py,sha256=c8M8UAYmIZ-vWZLeKD2jMj4EDCJbr9QR8Jq_
262
264
  omlish/formats/json/stream/lex.py,sha256=ItsWvtl5SZH-HwQtPy8Cpf4nszqDzvUTdIOEmSRiZ-E,6807
263
265
  omlish/formats/json/stream/parse.py,sha256=JuYmXwtTHmQJTFKoJNoEHUpCPxXdl_gvKPykVXgED34,6208
264
266
  omlish/formats/json/stream/render.py,sha256=NtmDsN92xZi5dkgSSuMeMXMAiJblmjz1arB4Ft7vBhc,3715
265
- omlish/formats/json5/Json5.g4,sha256=fSUikG4-eK3j0Ugab9FzQZgpN3w0dN2gjSPWXmPcybI,2661
267
+ omlish/formats/json5/Json5.g4,sha256=ZUmgJPvj8lSMUD_v3wijp10ZQExYB5mu5Q089dYEJSU,2389
266
268
  omlish/formats/json5/__init__.py,sha256=BsjPz5zJDji3GjQ8x8hWvcl1GYPV_ZIHnE3c2Sr8aTU,102
267
269
  omlish/formats/json5/codec.py,sha256=ldnxCRo0JP1fkGLt0mMxJlLvNxqIF_1KUCcSp1HtI-M,452
268
270
  omlish/formats/json5/errors.py,sha256=AHkR9ySjAoQdUrizpqgL8fg0M5oe5mHZkml3KZHEvC4,38
@@ -299,19 +301,20 @@ omlish/http/consts.py,sha256=7BJ4D1MdIvqBcepkgCfBFHolgTwbOlqsOEiee_IjxOA,2289
299
301
  omlish/http/cookies.py,sha256=uuOYlHR6e2SC3GM41V0aozK10nef9tYg83Scqpn5-HM,6351
300
302
  omlish/http/dates.py,sha256=Otgp8wRxPgNGyzx8LFowu1vC4EKJYARCiAwLFncpfHM,2875
301
303
  omlish/http/encodings.py,sha256=w2WoKajpaZnQH8j-IBvk5ZFL2O2pAU_iBvZnkocaTlw,164
302
- omlish/http/handlers.py,sha256=2bKw7XRM11C0VSx-DStKa6exFKNINKK4jZ3uVUVh5d8,795
304
+ omlish/http/handlers.py,sha256=_MdO62GGKqzCabSSmA9uCMTB41b6sSC0AFJCpPJ9vOU,1232
303
305
  omlish/http/headers.py,sha256=ZMmjrEiYjzo0YTGyK0YsvjdwUazktGqzVVYorY4fd44,5081
304
306
  omlish/http/json.py,sha256=9XwAsl4966Mxrv-1ytyCqhcE6lbBJw-0_tFZzGszgHE,7440
305
307
  omlish/http/jwt.py,sha256=6Rigk1WrJ059DY4jDIKnxjnChWb7aFdermj2AI2DSvk,4346
306
308
  omlish/http/multipart.py,sha256=R9ycpHsXRcmh0uoc43aYb7BdWL-8kSQHe7J-M81aQZM,2240
307
309
  omlish/http/parsing.py,sha256=hxfd9nYaAAjYIivkTClFZXMRmiiCnxzeeEIGXw7-gt0,13992
308
- omlish/http/sessions.py,sha256=WVRTy2KjehwQiYTPn7r44gZ4Pqg8sDC_9-wiYON0344,4796
310
+ omlish/http/sessions.py,sha256=TfTJ_j-6c9PelG_RmijEwozfaVm3O7YzgtFvp8VzQqM,4799
311
+ omlish/http/simple.py,sha256=9WtpbQahiZE-UjRP3ZDni8DQTq_HkVSdwpui_y8mf1I,2867
309
312
  omlish/http/sse.py,sha256=MDs9RvxQXoQliImcc6qK1ERajEYM7Q1l8xmr-9ceNBc,2315
310
313
  omlish/http/versions.py,sha256=wSiOXPiClVjkVgSU_VmxkoD1SUYGaoPbP0U5Aw-Ufg8,409
311
314
  omlish/http/wsgi.py,sha256=czZsVUX-l2YTlMrUjKN49wRoP4rVpS0qpeBn4O5BoMY,948
312
315
  omlish/http/coro/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
313
316
  omlish/http/coro/fdio.py,sha256=ajj_lekRockGwQEw8m_mi6RO9-o6hnC9ITiwtZe3y-s,4017
314
- omlish/http/coro/server.py,sha256=-e-J5pPqPDGrvQkwcukwltOjTbTNatiCx9Rl7FvooTI,18071
317
+ omlish/http/coro/server.py,sha256=QujEUM2fhfy2GsoKhpHZvFv7SlGVwcU8kwUXEyUgwWk,18791
315
318
  omlish/inject/__init__.py,sha256=n0RC9UDGsBQQ39cST39-XJqJPq2M0tnnh9yJubW9azo,1891
316
319
  omlish/inject/binder.py,sha256=DAbc8TZi5w8Mna0TUtq0mT4jeDVA7i7SlBtOFrh2swc,4185
317
320
  omlish/inject/bindings.py,sha256=pLXn2U3kvmAS-68IOG-tr77DbiI-wp9hGyy4lhG6_H8,525
@@ -373,7 +376,7 @@ omlish/io/fdio/pollers.py,sha256=yNadAt3W5wd90PFmd3vD77bq5QwoVb2A6SM2JjZpKRs,550
373
376
  omlish/iterators/__init__.py,sha256=yMavf5FofiS1EU4UFuWPXiFZ03W0H-y7MuMxW8FUaEE,358
374
377
  omlish/iterators/iterators.py,sha256=ghI4dO6WPyyFOLTIIMaHQ_IOy2xXaFpGPqveZ5YGIBU,3158
375
378
  omlish/iterators/recipes.py,sha256=53mkexitMhkwXQZbL6DrhpT0WePQ_56uXd5Jaw3DfzI,467
376
- omlish/iterators/tools.py,sha256=SvXyyQJh7aceLYhRl6pQB-rfSaXw5IMIWukeEeOZt-0,2492
379
+ omlish/iterators/tools.py,sha256=Pi4ybXytUXVZ3xwK89xpPImQfYYId9p1vIFQvVqVLqA,2551
377
380
  omlish/iterators/unique.py,sha256=0jAX3kwzVfRNhe0Tmh7kVP_Q2WBIn8POo_O-rgFV0rQ,1390
378
381
  omlish/lang/__init__.py,sha256=sY7YSgN772n48qWlR-mwuOOCOwRF5Fh421gZqZWxYlw,4042
379
382
  omlish/lang/cached.py,sha256=92TvRZQ6sWlm7dNn4hgl7aWKbX0J1XUEo3DRjBpgVQk,7834
@@ -429,13 +432,15 @@ omlish/lite/types.py,sha256=fP5EMyBdEp2LmDxcHjUDtwAMdR06ISr9lKOL7smWfHM,140
429
432
  omlish/lite/typing.py,sha256=U3-JaEnkDSYxK4tsu_MzUn3RP6qALBe5FXQXpD-licE,1090
430
433
  omlish/logs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
431
434
  omlish/logs/abc.py,sha256=ho4ABKYMKX-V7g4sp1BByuOLzslYzLlQ0MESmjEpT-o,8005
432
- omlish/logs/all.py,sha256=4Z6cNB0E1xbX0IOQWZEWLA0Jw-yyjhXa3PD_Nvfewu8,556
435
+ omlish/logs/all.py,sha256=Er2NIcDvlMpuAcRr9b_uMHeoERU7I6lu5oLrDGRdV0U,728
436
+ omlish/logs/callers.py,sha256=W0BdEtuGkQ0JM-FCsXQIBQCsNUbIsbDrtCaJy9DStk4,1143
433
437
  omlish/logs/color.py,sha256=CM-ceoPXs0j5_klnZDJkFCFRgHOToFzJyLjC6LsnPEk,665
434
438
  omlish/logs/configs.py,sha256=XOc8rWxfPpPMxJESVD2mLCUoLtbQnGnZwvYhhqe7DD8,772
435
439
  omlish/logs/filters.py,sha256=2noFRyBez3y519fpfsDSt1vo8wX-85b8sMXZi5o_xyE,208
436
440
  omlish/logs/handlers.py,sha256=zgSnKQA5q9Fu7T0Nkd7twog9H1Wg9-bDCzz4_F1TOBo,319
437
441
  omlish/logs/json.py,sha256=zyqMWpZY3lk4WRk4wgmataBomGX9S3iDsydiM1sS-lI,1366
438
442
  omlish/logs/noisy.py,sha256=Ubc-eTH6ZbGYsLfUUi69JAotwuUwzb-SJBeGo_0dIZI,348
443
+ omlish/logs/protocol.py,sha256=NzyCeNBN-fyKpJinhECfjUQSd5MxZLiYbuLCTtW6QUU,4500
439
444
  omlish/logs/proxy.py,sha256=A-ROPUUAlF397qTbEqhel6YhQMstNuXL3Xmts7w9dAo,2347
440
445
  omlish/logs/standard.py,sha256=FbKdF2Z4Na5i2TNwKn0avLJXyICe2JKsPufjvKCHGn0,3162
441
446
  omlish/logs/utils.py,sha256=mzHrZ9ji75p5A8qR29eUr05CBAHMb8J753MSkID_VaQ,393
@@ -496,18 +501,24 @@ omlish/reflect/inspect.py,sha256=veJ424-9oZrqyvhVpvxOi7hcKW-PDBkdYL2yjrFlk4o,495
496
501
  omlish/reflect/ops.py,sha256=RJ6jzrM4ieFsXzWyNXWV43O_WgzEaUvlHSc5N2ezW2A,2044
497
502
  omlish/reflect/subst.py,sha256=g3q7NmNWsmc67mcchmCE3WFPCMDSBq-FXn4ah-DWL_U,3622
498
503
  omlish/reflect/types.py,sha256=lYxK_hlC4kVDMKeDYJp0mymSth21quwuFAMAEFBznyE,9151
499
- omlish/secrets/__init__.py,sha256=SGB1KrlNrxlNpazEHYy95NTzteLi8ndoEgMhU7luBl8,420
504
+ omlish/secrets/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
505
+ omlish/secrets/all.py,sha256=zRp3bYkcVG4Aez4hBHKBxc07s6u74IrGQVUB8cfrGxY,281
500
506
  omlish/secrets/crypto.py,sha256=6CsLy0UEqCrBK8Xx_3-iFF6SKtu2GlEqUQ8-MliY3tk,3709
501
507
  omlish/secrets/marshal.py,sha256=U9uSRTWzZmumfNZeh_dROwVdGrARsp155TylRbjilP8,2048
502
508
  omlish/secrets/openssl.py,sha256=wxA_wIlxtuOUy71ABxAJgavh-UI_taOfm-A0dVlmSwM,6219
503
509
  omlish/secrets/pwgen.py,sha256=v-5ztnOTHTAWXLGR-3H6HkMj2nPIZBMbo5xWR3q0rDY,1707
504
510
  omlish/secrets/pwhash.py,sha256=Goktn-swmC6PXqfRBnDrH_Lr42vjckT712UyErPjzkw,4102
505
- omlish/secrets/secrets.py,sha256=cnDGBoPknVxsCN04_gqcJT_7Ebk3iO3VPkRZ2oMjkMw,7868
511
+ omlish/secrets/secrets.py,sha256=QNgOmRcIRK2fx49bIbBBM2rYbe6IhhLgk8fKvq8guoI,7963
506
512
  omlish/secrets/subprocesses.py,sha256=ffjfbgPbEE_Pwb_87vG4yYR2CGZy3I31mHNCo_0JtHw,1212
507
513
  omlish/sockets/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
508
- omlish/sockets/addresses.py,sha256=ZQFacDsXo6cKSgEjzN525IcUJPyfubXETzbY-_BBAro,1285
509
- omlish/sockets/handlers.py,sha256=9kkNMj1DTJa4xo_3hcBvSkjKc-dy_Ho5he2ubJieJ2A,621
510
- omlish/sockets/server.py,sha256=96vCNBvHSf8lWI3kd3RBbY0M2qXGaD_TksMhnBQ0_q0,1600
514
+ omlish/sockets/addresses.py,sha256=vbVeQBkzI513H4vRv-JS89QtRbr9U8v5zqkm3oODl_s,1869
515
+ omlish/sockets/bind.py,sha256=rNX-1VWYR0IlOLo4S0qqfm1PwqfjvSvHiFj7DE2_gIE,7914
516
+ omlish/sockets/handlers.py,sha256=ux2cPzAWV8b-mQ0K08-b7qjVeIT8Js5_-tyVZs0fbwg,406
517
+ omlish/sockets/io.py,sha256=lfhTkB7NnAIx9kuQhAkwgsEUXY78Mp1_WtYrIQNS_k8,1408
518
+ omlish/sockets/server/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
519
+ omlish/sockets/server/handlers.py,sha256=-5lH2Xg7gnZiPB4t2Asa_Vgblj1ZkHzLvyiC_K4XlNc,3295
520
+ omlish/sockets/server/server.py,sha256=kIQ8hHpc9GVefX7sGUrs6bhpJybaagYVwKq5QRT5B4s,4463
521
+ omlish/sockets/server/threading.py,sha256=YmW3Ym_p5j_F4SIH9BgRHIObywjq1HS39j9CGWIcMAY,2856
511
522
  omlish/specs/__init__.py,sha256=zZwF8yXTEkSstYtORkDhVLK-_hWU8WOJCuBpognb_NY,118
512
523
  omlish/specs/jmespath/LICENSE,sha256=IH-ZZlZkS8XMkf_ubNVD1aYHQ2l_wd0tmHtXrCcYpRU,1113
513
524
  omlish/specs/jmespath/__init__.py,sha256=9tsrquw1kXe1KAhTP3WeL0GlGBiTguQVxsC-lUYTWP4,2087
@@ -552,14 +563,14 @@ omlish/specs/openapi/openapi.py,sha256=y4h04jeB7ORJSVrcy7apaBdpwLjIyscv1Ub5SderH
552
563
  omlish/sql/__init__.py,sha256=TpZLsEJKJzvJ0eMzuV8hwOJJbkxBCV1RZPUMLAVB6io,173
553
564
  omlish/sql/abc.py,sha256=NfbcIlEvdEu6vn0TolhfYb2SO5uzUmY0kARCbg6uVAU,1879
554
565
  omlish/sql/dbapi.py,sha256=5ghJH-HexsmDlYdWlhf00nCGQX2IC98_gxIxMkucOas,3195
555
- omlish/sql/dbs.py,sha256=lpdFmm2vTwLoBiVYGj9yPsVcTEYYNCxlYZZpjfChzkY,1870
566
+ omlish/sql/dbs.py,sha256=65e388987upJpsFX8bNL7uhiYv2sCsmk9Y04V0MXdsI,1873
556
567
  omlish/sql/params.py,sha256=Z4VPet6GhNqD1T_MXSWSHkdy3cpUEhST-OplC4B_fYI,4433
557
568
  omlish/sql/qualifiedname.py,sha256=rlW3gVmyucJbqwcxj_7BfK4X2HoXrMroZT2H45zPgJQ,2264
558
569
  omlish/sql/alchemy/__init__.py,sha256=1ruDMiviH5fjevn2xVki-QspcE9O3VPy4hxOqpHjI2s,224
559
570
  omlish/sql/alchemy/asyncs.py,sha256=MwZwWIaZsUCQLcTA8mdHUPZmR-pXEVSAsvd15FCm3W4,3692
560
571
  omlish/sql/alchemy/duckdb.py,sha256=kr7pIhiBLNAuZrcigHDtFg9zHkVcrRW3LfryO9VJ4mk,3749
561
572
  omlish/sql/alchemy/exprs.py,sha256=gO4Fj4xEY-PuDgV-N8hBMy55glZz7O-4H7v1LWabfZY,323
562
- omlish/sql/alchemy/secrets.py,sha256=EMfy4EfTbEvrlv_41oOhn8qsoF-eTkY7HciPenIE6rI,178
573
+ omlish/sql/alchemy/secrets.py,sha256=WEeaec1ejQcE3Yaa7p5BSP9AMGEzy1lwr7QMSRL0VBw,180
563
574
  omlish/sql/alchemy/sqlean.py,sha256=RbkuOuFIfM4fowwKk8-sQ6Dxk-tTUwxS94nY5Kxt52s,403
564
575
  omlish/sql/queries/__init__.py,sha256=8wdq6PBf5YzqQWFu-CE8om6BN38sDAD9UEz9VzkojzM,1337
565
576
  omlish/sql/queries/base.py,sha256=_8O3MbH_OEjBnhp2oIJUZ3ClaQ8l4Sj9BdPdsP0Ie-g,224
@@ -628,9 +639,9 @@ omlish/text/indent.py,sha256=YjtJEBYWuk8--b9JU_T6q4yxV85_TR7VEVr5ViRCFwk,1336
628
639
  omlish/text/minja.py,sha256=jZC-fp3Xuhx48ppqsf2Sf1pHbC0t8XBB7UpUUoOk2Qw,5751
629
640
  omlish/text/parts.py,sha256=7vPF1aTZdvLVYJ4EwBZVzRSy8XB3YqPd7JwEnNGGAOo,6495
630
641
  omlish/text/random.py,sha256=jNWpqiaKjKyTdMXC-pWAsSC10AAP-cmRRPVhm59ZWLk,194
631
- omlish-0.0.0.dev217.dist-info/LICENSE,sha256=B_hVtavaA8zCYDW99DYdcpDLKz1n3BBRjZrcbv8uG8c,1451
632
- omlish-0.0.0.dev217.dist-info/METADATA,sha256=ej8P7o2EGJWFumDVus7JjRA14H1OZPQWWqQ_mB7vRhE,4176
633
- omlish-0.0.0.dev217.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
634
- omlish-0.0.0.dev217.dist-info/entry_points.txt,sha256=Lt84WvRZJskWCAS7xnQGZIeVWksprtUHj0llrvVmod8,35
635
- omlish-0.0.0.dev217.dist-info/top_level.txt,sha256=pePsKdLu7DvtUiecdYXJ78iO80uDNmBlqe-8hOzOmfs,7
636
- omlish-0.0.0.dev217.dist-info/RECORD,,
642
+ omlish-0.0.0.dev219.dist-info/LICENSE,sha256=B_hVtavaA8zCYDW99DYdcpDLKz1n3BBRjZrcbv8uG8c,1451
643
+ omlish-0.0.0.dev219.dist-info/METADATA,sha256=lh7Dpy8tG4NhG-VPo4QWw-EnYsyHj1OY8pnJOIEfQm8,4176
644
+ omlish-0.0.0.dev219.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
645
+ omlish-0.0.0.dev219.dist-info/entry_points.txt,sha256=Lt84WvRZJskWCAS7xnQGZIeVWksprtUHj0llrvVmod8,35
646
+ omlish-0.0.0.dev219.dist-info/top_level.txt,sha256=pePsKdLu7DvtUiecdYXJ78iO80uDNmBlqe-8hOzOmfs,7
647
+ omlish-0.0.0.dev219.dist-info/RECORD,,