omlish 0.0.0.dev217__py3-none-any.whl → 0.0.0.dev219__py3-none-any.whl

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