omlish 0.0.0.dev242__py3-none-any.whl → 0.0.0.dev243__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
omlish/__about__.py CHANGED
@@ -1,5 +1,5 @@
1
- __version__ = '0.0.0.dev242'
2
- __revision__ = '0866b8cd6f11d42061b0949c01a15583a1a6b39d'
1
+ __version__ = '0.0.0.dev243'
2
+ __revision__ = '97467f9facc16b72c3dac69aba18c543dce228b1'
3
3
 
4
4
 
5
5
  #
@@ -0,0 +1,45 @@
1
+ # ruff: noqa: UP006 UP007
2
+ # @omlish-lite
3
+ import asyncio
4
+ import typing as ta
5
+
6
+ from ...lite.timeouts import Timeout
7
+ from ...lite.timeouts import TimeoutLike
8
+
9
+
10
+ async def asyncio_wait_until_can_connect(
11
+ host: ta.Any = None,
12
+ port: ta.Any = None,
13
+ *,
14
+ timeout: ta.Optional[TimeoutLike] = None,
15
+ on_fail: ta.Optional[ta.Callable[[BaseException], None]] = None,
16
+ sleep_s: float = .1,
17
+ exception: ta.Union[ta.Type[BaseException], ta.Tuple[ta.Type[BaseException], ...]] = (Exception,),
18
+ ) -> None:
19
+ timeout = Timeout.of(timeout)
20
+
21
+ async def inner():
22
+ while True:
23
+ timeout()
24
+
25
+ try:
26
+ reader, writer = await asyncio.open_connection(host, port)
27
+
28
+ except asyncio.CancelledError:
29
+ raise
30
+
31
+ except exception as e: # noqa
32
+ if on_fail is not None:
33
+ on_fail(e)
34
+
35
+ else:
36
+ writer.close()
37
+ await asyncio.wait_for(writer.wait_closed(), timeout=timeout.or_(None))
38
+ break
39
+
40
+ await asyncio.sleep(min(sleep_s, timeout.remaining()))
41
+
42
+ if timeout() != float('inf'):
43
+ await asyncio.wait_for(inner(), timeout=timeout())
44
+ else:
45
+ await inner()
omlish/lang/__init__.py CHANGED
@@ -54,18 +54,15 @@ from .cmp import ( # noqa
54
54
 
55
55
  from .contextmanagers import ( # noqa
56
56
  AsyncContextManager,
57
- AsyncExitStacked,
58
57
  ContextManaged,
59
58
  ContextManager,
60
59
  ContextWrapped,
61
60
  DefaultLockable,
62
- ExitStacked,
63
61
  Lockable,
64
62
  NOP_CONTEXT_MANAGER,
65
63
  NopContextManager,
66
64
  Timer,
67
65
  a_defer,
68
- attr_setting,
69
66
  breakpoint_on_exception,
70
67
  context_var_setting,
71
68
  context_wrapped,
@@ -232,6 +229,12 @@ from .typing import ( # noqa
232
229
 
233
230
  ##
234
231
 
232
+ from ..lite.contextmanagers import ( # noqa
233
+ attr_setting,
234
+ AsyncExitStacked,
235
+ ExitStacked,
236
+ )
237
+
235
238
  from ..lite.imports import ( # noqa
236
239
  import_attr,
237
240
  import_module,
@@ -170,103 +170,6 @@ def context_var_setting(var: contextvars.ContextVar[T], val: T) -> ta.Iterator[T
170
170
  var.reset(token)
171
171
 
172
172
 
173
- @contextlib.contextmanager
174
- def attr_setting(obj, attr, val, *, default=None): # noqa
175
- not_set = object()
176
- orig = getattr(obj, attr, not_set)
177
- try:
178
- setattr(obj, attr, val)
179
- if orig is not not_set:
180
- yield orig
181
- else:
182
- yield default
183
- finally:
184
- if orig is not_set:
185
- delattr(obj, attr)
186
- else:
187
- setattr(obj, attr, orig)
188
-
189
-
190
- ##
191
-
192
-
193
- class ExitStacked:
194
- @property
195
- def _exit_stack(self) -> contextlib.ExitStack:
196
- try:
197
- return self.__exit_stack # type: ignore
198
- except AttributeError:
199
- es = self.__exit_stack = contextlib.ExitStack()
200
- return es
201
-
202
- def _enter_context(self, context_manager: ta.ContextManager[T]) -> T:
203
- return self._exit_stack.enter_context(ta.cast(ta.ContextManager, context_manager))
204
-
205
- def __enter__(self) -> ta.Self:
206
- try:
207
- superfn = super().__enter__ # type: ignore
208
- except AttributeError:
209
- ret = self
210
- else:
211
- ret = superfn()
212
- self._exit_stack.__enter__()
213
- return ret
214
-
215
- def __exit__(
216
- self,
217
- exc_type: type[BaseException] | None,
218
- exc_val: BaseException | None,
219
- exc_tb: types.TracebackType | None,
220
- ) -> bool | None:
221
- self._exit_stack.__exit__(exc_type, exc_val, exc_tb)
222
- try:
223
- superfn = super().__exit__ # type: ignore
224
- except AttributeError:
225
- return None
226
- else:
227
- return superfn(exc_type, exc_val, exc_tb)
228
-
229
-
230
- class AsyncExitStacked:
231
- @property
232
- def _exit_stack(self) -> contextlib.AsyncExitStack:
233
- try:
234
- return self.__exit_stack # type: ignore
235
- except AttributeError:
236
- es = self.__exit_stack = contextlib.AsyncExitStack()
237
- return es
238
-
239
- async def _enter_async_context(self, context_manager: ta.AsyncContextManager[T]) -> T:
240
- return await self._exit_stack.enter_async_context(ta.cast(ta.AsyncContextManager, context_manager))
241
-
242
- def _enter_context(self, context_manager: ta.ContextManager[T]) -> T:
243
- return self._exit_stack.enter_context(ta.cast(ta.ContextManager, context_manager))
244
-
245
- async def __aenter__(self) -> ta.Self:
246
- try:
247
- superfn = super().__aenter__ # type: ignore
248
- except AttributeError:
249
- ret = self
250
- else:
251
- ret = await superfn()
252
- await self._exit_stack.__aenter__()
253
- return ret
254
-
255
- async def __aexit__(
256
- self,
257
- exc_type: type[BaseException] | None,
258
- exc_val: BaseException | None,
259
- exc_tb: types.TracebackType | None,
260
- ) -> bool | None:
261
- await self._exit_stack.__aexit__(exc_type, exc_val, exc_tb)
262
- try:
263
- superfn = super().__aexit__ # type: ignore
264
- except AttributeError:
265
- return None
266
- else:
267
- return await superfn(exc_type, exc_val, exc_tb)
268
-
269
-
270
173
  ##
271
174
 
272
175
 
@@ -1,5 +1,6 @@
1
1
  # ruff: noqa: UP007
2
2
  import contextlib
3
+ import sys
3
4
  import typing as ta
4
5
 
5
6
  from .check import check
@@ -14,20 +15,64 @@ AsyncExitStackedT = ta.TypeVar('AsyncExitStackedT', bound='AsyncExitStacked')
14
15
 
15
16
 
16
17
  class ExitStacked:
18
+ def __init_subclass__(cls, **kwargs: ta.Any) -> None:
19
+ super().__init_subclass__(**kwargs)
20
+
21
+ for a in ('__enter__', '__exit__'):
22
+ for b in cls.__bases__:
23
+ if b is ExitStacked:
24
+ continue
25
+ try:
26
+ fn = getattr(b, a)
27
+ except AttributeError:
28
+ pass
29
+ else:
30
+ if fn is not getattr(ExitStacked, a):
31
+ raise TypeError(f'ExitStacked subclass {cls} must not not override {a} via {b}')
32
+
17
33
  _exit_stack: ta.Optional[contextlib.ExitStack] = None
18
34
 
19
- def __enter__(self: ExitStackedT) -> ExitStackedT:
20
- check.state(self._exit_stack is None)
21
- es = self._exit_stack = contextlib.ExitStack()
22
- es.__enter__()
23
- return self
35
+ @contextlib.contextmanager
36
+ def _exit_stacked_init_wrapper(self) -> ta.Iterator[None]:
37
+ """
38
+ Overridable wrapper around __enter__ which deliberately does not have access to an _exit_stack yet. Intended for
39
+ things like wrapping __enter__ in a lock.
40
+ """
41
+
42
+ yield
24
43
 
44
+ @ta.final
45
+ def __enter__(self: ExitStackedT) -> ExitStackedT:
46
+ """
47
+ Final because any contexts entered during this init must be exited if any exception is thrown, and user
48
+ overriding would likely interfere with that. Override `_enter_contexts` for such init.
49
+ """
50
+
51
+ with self._exit_stacked_init_wrapper():
52
+ check.state(self._exit_stack is None)
53
+ es = self._exit_stack = contextlib.ExitStack()
54
+ es.__enter__()
55
+ try:
56
+ self._enter_contexts()
57
+ except Exception: # noqa
58
+ es.__exit__(*sys.exc_info())
59
+ raise
60
+ return self
61
+
62
+ @ta.final
25
63
  def __exit__(self, exc_type, exc_val, exc_tb):
26
64
  if (es := self._exit_stack) is None:
27
65
  return None
28
- self._exit_contexts()
66
+ try:
67
+ self._exit_contexts()
68
+ except Exception: # noqa
69
+ es.__exit__(*sys.exc_info())
70
+ raise
29
71
  return es.__exit__(exc_type, exc_val, exc_tb)
30
72
 
73
+ def _enter_contexts(self) -> None:
74
+ pass
75
+
31
76
  def _exit_contexts(self) -> None:
32
77
  pass
33
78
 
@@ -37,20 +82,54 @@ class ExitStacked:
37
82
 
38
83
 
39
84
  class AsyncExitStacked:
85
+ def __init_subclass__(cls, **kwargs: ta.Any) -> None:
86
+ super().__init_subclass__(**kwargs)
87
+
88
+ for a in ('__aenter__', '__aexit__'):
89
+ for b in cls.__bases__:
90
+ if b is AsyncExitStacked:
91
+ continue
92
+ try:
93
+ fn = getattr(b, a)
94
+ except AttributeError:
95
+ pass
96
+ else:
97
+ if fn is not getattr(AsyncExitStacked, a):
98
+ raise TypeError(f'AsyncExitStacked subclass {cls} must not not override {a} via {b}')
99
+
40
100
  _exit_stack: ta.Optional[contextlib.AsyncExitStack] = None
41
101
 
42
- async def __aenter__(self: AsyncExitStackedT) -> AsyncExitStackedT:
43
- check.state(self._exit_stack is None)
44
- es = self._exit_stack = contextlib.AsyncExitStack()
45
- await es.__aenter__()
46
- return self
102
+ @contextlib.asynccontextmanager
103
+ async def _async_exit_stacked_init_wrapper(self) -> ta.AsyncGenerator[None, None]:
104
+ yield
47
105
 
106
+ @ta.final
107
+ async def __aenter__(self: AsyncExitStackedT) -> AsyncExitStackedT:
108
+ async with self._async_exit_stacked_init_wrapper():
109
+ check.state(self._exit_stack is None)
110
+ es = self._exit_stack = contextlib.AsyncExitStack()
111
+ await es.__aenter__()
112
+ try:
113
+ await self._async_enter_contexts()
114
+ except Exception: # noqa
115
+ await es.__aexit__(*sys.exc_info())
116
+ raise
117
+ return self
118
+
119
+ @ta.final
48
120
  async def __aexit__(self, exc_type, exc_val, exc_tb):
49
121
  if (es := self._exit_stack) is None:
50
122
  return None
51
- await self._async_exit_contexts()
123
+ try:
124
+ await self._async_exit_contexts()
125
+ except Exception: # noqa
126
+ await es.__aexit__(*sys.exc_info())
127
+ raise
52
128
  return await es.__aexit__(exc_type, exc_val, exc_tb)
53
129
 
130
+ async def _async_enter_contexts(self) -> None:
131
+ pass
132
+
54
133
  async def _async_exit_contexts(self) -> None:
55
134
  pass
56
135
 
omlish/logs/protocol.py CHANGED
@@ -23,25 +23,25 @@ class Logging(ta.Protocol):
23
23
 
24
24
  #
25
25
 
26
- def debug(self, msg: str, *args, **kwargs) -> None:
26
+ def debug(self, msg: str, *args: ta.Any, **kwargs: ta.Any) -> None:
27
27
  ...
28
28
 
29
- def info(self, msg: str, *args, **kwargs) -> None:
29
+ def info(self, msg: str, *args: ta.Any, **kwargs: ta.Any) -> None:
30
30
  ...
31
31
 
32
- def warning(self, msg: str, *args, **kwargs) -> None:
32
+ def warning(self, msg: str, *args: ta.Any, **kwargs: ta.Any) -> None:
33
33
  ...
34
34
 
35
- def error(self, msg: str, *args, **kwargs) -> None:
35
+ def error(self, msg: str, *args: ta.Any, **kwargs: ta.Any) -> None:
36
36
  ...
37
37
 
38
- def exception(self, msg: str, *args, exc_info=True, **kwargs) -> None:
38
+ def exception(self, msg: str, *args: ta.Any, exc_info: bool = True, **kwargs) -> None:
39
39
  ...
40
40
 
41
- def critical(self, msg: str, *args, **kwargs) -> None:
41
+ def critical(self, msg: str, *args: ta.Any, **kwargs: ta.Any) -> None:
42
42
  ...
43
43
 
44
- def log(self, level: LogLevel, msg: str, *args, **kwargs) -> None:
44
+ def log(self, level: LogLevel, msg: str, *args: ta.Any, **kwargs: ta.Any) -> None:
45
45
  ...
46
46
 
47
47
 
@@ -66,30 +66,30 @@ class AbstractLogging(abc.ABC):
66
66
 
67
67
  #
68
68
 
69
- def debug(self, msg: str, *args, **kwargs) -> None:
69
+ def debug(self, msg: str, *args: ta.Any, **kwargs: ta.Any) -> None:
70
70
  if self.is_enabled_for(logging.DEBUG):
71
71
  self.log(logging.DEBUG, msg, args, **kwargs)
72
72
 
73
- def info(self, msg: str, *args, **kwargs) -> None:
73
+ def info(self, msg: str, *args: ta.Any, **kwargs: ta.Any) -> None:
74
74
  if self.is_enabled_for(logging.INFO):
75
75
  self.log(logging.INFO, msg, args, **kwargs)
76
76
 
77
- def warning(self, msg: str, *args, **kwargs) -> None:
77
+ def warning(self, msg: str, *args: ta.Any, **kwargs: ta.Any) -> None:
78
78
  if self.is_enabled_for(logging.WARNING):
79
79
  self.log(logging.WARNING, msg, args, **kwargs)
80
80
 
81
- def error(self, msg: str, *args, **kwargs) -> None:
81
+ def error(self, msg: str, *args: ta.Any, **kwargs: ta.Any) -> None:
82
82
  if self.is_enabled_for(logging.ERROR):
83
83
  self.log(logging.ERROR, msg, args, **kwargs)
84
84
 
85
- def exception(self, msg: str, *args, exc_info=True, **kwargs) -> None:
85
+ def exception(self, msg: str, *args: ta.Any, exc_info: bool = True, **kwargs: ta.Any) -> None:
86
86
  self.error(msg, *args, exc_info=exc_info, **kwargs)
87
87
 
88
- def critical(self, msg: str, *args, **kwargs) -> None:
88
+ def critical(self, msg: str, *args: ta.Any, **kwargs: ta.Any) -> None:
89
89
  if self.is_enabled_for(logging.CRITICAL):
90
90
  self.log(logging.CRITICAL, msg, args, **kwargs)
91
91
 
92
- def log(self, level: LogLevel, msg: str, *args, **kwargs) -> None:
92
+ def log(self, level: LogLevel, msg: str, *args: ta.Any, **kwargs: ta.Any) -> None:
93
93
  if not isinstance(level, int):
94
94
  raise TypeError('Level must be an integer.')
95
95
  if self.is_enabled_for(level):
@@ -2,11 +2,14 @@
2
2
  # ruff: noqa: UP006 UP007
3
3
  import abc
4
4
  import contextlib
5
+ import enum
5
6
  import logging
6
7
  import selectors
7
8
  import threading
8
9
  import typing as ta
9
10
 
11
+ from ...lite.contextmanagers import ExitStacked
12
+ from ...lite.contextmanagers import defer
10
13
  from ..addresses import SocketAndAddress
11
14
  from ..bind import SocketBinder
12
15
  from ..io import close_socket_immediately
@@ -76,58 +79,88 @@ class SocketServer(abc.ABC):
76
79
 
77
80
  #
78
81
 
79
- @contextlib.contextmanager
80
- def _listen_context(self) -> ta.Iterator[SelectorProtocol]:
81
- with contextlib.ExitStack() as es:
82
- es.enter_context(self._lock)
83
- es.enter_context(self._binder)
82
+ class PollResult(enum.Enum):
83
+ TIMEOUT = enum.auto()
84
+ CONNECTION = enum.auto()
85
+ ERROR = enum.auto()
86
+ SHUTDOWN = enum.auto()
84
87
 
85
- self._binder.listen()
88
+ class PollContext(ExitStacked, abc.ABC):
89
+ @abc.abstractmethod
90
+ def poll(self, timeout: ta.Optional[float] = None) -> 'SocketServer.PollResult':
91
+ raise NotImplementedError
86
92
 
87
- self._is_shutdown.clear()
88
- try:
89
- # XXX: Consider using another file descriptor or connecting to the socket to wake this up instead of
90
- # polling. Polling reduces our responsiveness to a shutdown request and wastes cpu at all other times.
91
- with self.Selector() as selector:
92
- selector.register(self._binder.fileno(), selectors.EVENT_READ)
93
+ class _PollContext(PollContext):
94
+ def __init__(self, server: 'SocketServer') -> None:
95
+ super().__init__()
93
96
 
94
- yield selector
97
+ self._server = server
95
98
 
96
- finally:
97
- self._is_shutdown.set()
99
+ _selector: ta.Any = None
98
100
 
99
- @contextlib.contextmanager
100
- def loop_context(self, poll_interval: ta.Optional[float] = None) -> ta.Iterator[ta.Iterator[bool]]:
101
- if poll_interval is None:
102
- poll_interval = self._poll_interval
101
+ def _enter_contexts(self) -> None:
102
+ self._enter_context(self._server._lock) # noqa: SLF001
103
+ self._enter_context(self._server._binder) # noqa: SLF001
103
104
 
104
- with self._listen_context() as selector:
105
- def loop():
106
- while not self._should_shutdown:
107
- ready = selector.select(poll_interval)
105
+ self._server._binder.listen() # noqa: SLF001
106
+
107
+ self._server._is_shutdown.clear() # noqa: SLF001
108
+ self._enter_context(defer(self._server._is_shutdown.set)) # noqa
109
+
110
+ # XXX: Consider using another file descriptor or connecting to the socket to wake this up instead of
111
+ # polling. Polling reduces our responsiveness to a shutdown request and wastes cpu at all other times.
112
+ self._selector = self._enter_context(self._server.Selector())
113
+ self._selector.register(self._server._binder.fileno(), selectors.EVENT_READ) # noqa: SLF001
108
114
 
109
- # bpo-35017: shutdown() called during select(), exit immediately.
110
- if self._should_shutdown:
111
- break # type: ignore[unreachable]
115
+ def poll(self, timeout: ta.Optional[float] = None) -> 'SocketServer.PollResult':
116
+ if self._server._should_shutdown: # noqa: SLF001
117
+ return SocketServer.PollResult.SHUTDOWN
112
118
 
113
- if ready:
114
- try:
115
- conn = self._binder.accept()
119
+ ready = self._selector.select(timeout)
116
120
 
117
- except OSError as exc:
118
- self._handle_error(exc)
121
+ # bpo-35017: shutdown() called during select(), exit immediately.
122
+ if self._server._should_shutdown: # noqa: SLF001
123
+ return SocketServer.PollResult.SHUTDOWN # type: ignore[unreachable]
119
124
 
120
- return
125
+ if not ready:
126
+ return SocketServer.PollResult.TIMEOUT
121
127
 
122
- try:
123
- self._handler(conn)
128
+ try:
129
+ conn = self._server._binder.accept() # noqa: SLF001
130
+
131
+ except OSError as exc:
132
+ self._server._handle_error(exc) # noqa: SLF001
124
133
 
125
- except Exception as exc: # noqa
126
- self._handle_error(exc, conn)
134
+ return SocketServer.PollResult.ERROR
127
135
 
128
- close_socket_immediately(conn.socket)
136
+ try:
137
+ self._server._handler(conn) # noqa: SLF001
129
138
 
130
- yield bool(ready)
139
+ except Exception as exc: # noqa
140
+ self._server._handle_error(exc, conn) # noqa: SLF001
141
+
142
+ close_socket_immediately(conn.socket)
143
+
144
+ return SocketServer.PollResult.CONNECTION
145
+
146
+ def poll_context(self) -> PollContext:
147
+ return self._PollContext(self)
148
+
149
+ #
150
+
151
+ @contextlib.contextmanager
152
+ def loop_context(self, poll_interval: ta.Optional[float] = None) -> ta.Iterator[ta.Iterator[bool]]:
153
+ if poll_interval is None:
154
+ poll_interval = self._poll_interval
155
+
156
+ with self.poll_context() as pc:
157
+ def loop():
158
+ while True:
159
+ res = pc.poll(poll_interval)
160
+ if res in (SocketServer.PollResult.ERROR, SocketServer.PollResult.SHUTDOWN):
161
+ return
162
+ else:
163
+ yield res == SocketServer.PollResult.CONNECTION
131
164
 
132
165
  yield loop()
133
166
 
omlish/sockets/wait.py ADDED
@@ -0,0 +1,39 @@
1
+ # ruff: noqa: UP006 UP007
2
+ # @omlish-lite
3
+ import socket
4
+ import threading
5
+ import typing as ta
6
+
7
+ from ..lite.timeouts import Timeout
8
+ from ..lite.timeouts import TimeoutLike
9
+
10
+
11
+ def socket_wait_until_can_connect(
12
+ address: ta.Any,
13
+ *,
14
+ timeout: ta.Optional[TimeoutLike] = None,
15
+ on_fail: ta.Optional[ta.Callable[[BaseException], None]] = None,
16
+ sleep_s: float = .1,
17
+ exception: ta.Union[ta.Type[BaseException], ta.Tuple[ta.Type[BaseException], ...]] = (Exception,),
18
+ cancel_event: ta.Optional[threading.Event] = None,
19
+ ) -> None:
20
+ timeout = Timeout.of(timeout)
21
+
22
+ if cancel_event is None:
23
+ cancel_event = threading.Event()
24
+
25
+ while not cancel_event.is_set():
26
+ timeout()
27
+
28
+ try:
29
+ conn = socket.create_connection(address, timeout=timeout.or_(None))
30
+
31
+ except exception as e: # noqa
32
+ if on_fail is not None:
33
+ on_fail(e)
34
+
35
+ else:
36
+ conn.close()
37
+ break
38
+
39
+ cancel_event.wait(min(sleep_s, timeout.remaining()))
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: omlish
3
- Version: 0.0.0.dev242
3
+ Version: 0.0.0.dev243
4
4
  Summary: omlish
5
5
  Author: wrmsr
6
6
  License: BSD-3-Clause
@@ -1,5 +1,5 @@
1
1
  omlish/.manifests.json,sha256=vQTAIvR8OblSq-uP2GUfnbei0RnmAnM5j0T1-OToh9E,8253
2
- omlish/__about__.py,sha256=v3KofXu74aLHjSY2AMiIiv61EfsLsoedesWKEUsNxWA,3380
2
+ omlish/__about__.py,sha256=3c_F9MxYda9rfa68tINgteoJ57COTQpld-0xkq1JRwY,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
@@ -101,6 +101,7 @@ omlish/asyncs/asyncio/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3h
101
101
  omlish/asyncs/asyncio/all.py,sha256=EksCHjRQKobiGrxuDW72IaH53WJMs7rdj_ZDBI3iKcg,315
102
102
  omlish/asyncs/asyncio/asyncio.py,sha256=mDjYNm1cylUhQ8slWXwdPoXasuWfafjzu78GHt2Mdig,2437
103
103
  omlish/asyncs/asyncio/channels.py,sha256=ZbmsEmdK1fV96liHdcVpRqA2dAMkXJt4Q3rFAg3YOIw,1074
104
+ omlish/asyncs/asyncio/sockets.py,sha256=Ni5O80fNAccSMAGrlSkZ923Nawxi3FHoXrKj4nr0xlU,1266
104
105
  omlish/asyncs/asyncio/streams.py,sha256=Uc9PCWSfBqrK2kdVtfjjQU1eaYTWYmZm8QISDj2xiuw,1004
105
106
  omlish/asyncs/asyncio/subprocesses.py,sha256=f30-wi-3n9R5dftm4CMrzp23EEa4GX283bORixm1_UU,6931
106
107
  omlish/asyncs/asyncio/timeouts.py,sha256=hokhi7jZSAtBv0ME3qL1cO5eshNA9ViEH7BLafNCBpQ,454
@@ -398,11 +399,11 @@ omlish/iterators/iterators.py,sha256=ghI4dO6WPyyFOLTIIMaHQ_IOy2xXaFpGPqveZ5YGIBU
398
399
  omlish/iterators/recipes.py,sha256=53mkexitMhkwXQZbL6DrhpT0WePQ_56uXd5Jaw3DfzI,467
399
400
  omlish/iterators/tools.py,sha256=Pi4ybXytUXVZ3xwK89xpPImQfYYId9p1vIFQvVqVLqA,2551
400
401
  omlish/iterators/unique.py,sha256=0jAX3kwzVfRNhe0Tmh7kVP_Q2WBIn8POo_O-rgFV0rQ,1390
401
- omlish/lang/__init__.py,sha256=2jxO7QWT0uOvdYdmBFgnqmVh-6I7DofsapgUl3wu1fY,4145
402
+ omlish/lang/__init__.py,sha256=T_hx_ygi-IqmeDPQ-uto2U4ZuAUDs-agOSAsF6WWLVI,4193
402
403
  omlish/lang/cached.py,sha256=tQaqMu1LID0q4NSTk5vPXsgxIBWSFAmjs5AhQoEHoCQ,7833
403
404
  omlish/lang/clsdct.py,sha256=sJYadm-fwzti-gsi98knR5qQUxriBmOqQE_qz3RopNk,1743
404
405
  omlish/lang/cmp.py,sha256=5vbzWWbqdzDmNKAGL19z6ZfUKe5Ci49e-Oegf9f4BsE,1346
405
- omlish/lang/contextmanagers.py,sha256=Mrn8NJ3pP0Zxi-IoGqSjZDdWUctsyee2vrZ2FtZvNmo,10529
406
+ omlish/lang/contextmanagers.py,sha256=UPH6daYwSP9cH5AfSVsJyEHk1UURMGhVPM5ZRhp_Hvw,7576
406
407
  omlish/lang/datetimes.py,sha256=ehI_DhQRM-bDxAavnp470XcekbbXc4Gdw9y1KpHDJT0,223
407
408
  omlish/lang/descriptors.py,sha256=mZ2h9zJ__MMpw8hByjRbAiONcwfVb6GD0btNnVi8C5w,6573
408
409
  omlish/lang/exceptions.py,sha256=qJBo3NU1mOWWm-NhQUHCY5feYXR3arZVyEHinLsmRH4,47
@@ -434,7 +435,7 @@ omlish/lite/__init__.py,sha256=ISLhM4q0LR1XXTCaHdZOZxBRyIsoZqYm4u0bf1BPcVk,148
434
435
  omlish/lite/cached.py,sha256=O7ozcoDNFm1Hg2wtpHEqYSp_i_nCLNOP6Ueq_Uk-7mU,1300
435
436
  omlish/lite/check.py,sha256=OLwtE2x6nlbGx4vS3Rda7zMHpgqzDSLJminTAX2lqLA,13529
436
437
  omlish/lite/configs.py,sha256=Ev_19sbII67pTWzInYjYqa9VyTiZBvyjhZqyG8TtufE,908
437
- omlish/lite/contextmanagers.py,sha256=ciaMl0D3QDHToM7M28-kwZ-Q48LtwgCxiud3nekgutA,2863
438
+ omlish/lite/contextmanagers.py,sha256=XSCwr9GpPBJxXR9Vr07M4A_BH3uLpZettyoSE5KqJu8,5566
438
439
  omlish/lite/dataclasses.py,sha256=t1G5-xOuvE6o6w9RyqHzLT9wHD0HkqBh5P8HUZWxGzs,1912
439
440
  omlish/lite/imports.py,sha256=o9WWrNrWg0hKeMvaj91giaovED_9VFanN2MyEHBGekY,1346
440
441
  omlish/lite/inject.py,sha256=-tTsOqqef-Ix5Tgl2DP_JAsNWJQDFUptERl3lk14Uzs,29007
@@ -462,7 +463,7 @@ omlish/logs/filters.py,sha256=2noFRyBez3y519fpfsDSt1vo8wX-85b8sMXZi5o_xyE,208
462
463
  omlish/logs/handlers.py,sha256=zgSnKQA5q9Fu7T0Nkd7twog9H1Wg9-bDCzz4_F1TOBo,319
463
464
  omlish/logs/json.py,sha256=zyqMWpZY3lk4WRk4wgmataBomGX9S3iDsydiM1sS-lI,1366
464
465
  omlish/logs/noisy.py,sha256=Ubc-eTH6ZbGYsLfUUi69JAotwuUwzb-SJBeGo_0dIZI,348
465
- omlish/logs/protocol.py,sha256=NzyCeNBN-fyKpJinhECfjUQSd5MxZLiYbuLCTtW6QUU,4500
466
+ omlish/logs/protocol.py,sha256=dfAR0_5kLEAkx0nhuWBhWMTVjWjhEl2uL-MxejrW1lk,4732
466
467
  omlish/logs/proxy.py,sha256=A-ROPUUAlF397qTbEqhel6YhQMstNuXL3Xmts7w9dAo,2347
467
468
  omlish/logs/standard.py,sha256=FbKdF2Z4Na5i2TNwKn0avLJXyICe2JKsPufjvKCHGn0,3162
468
469
  omlish/logs/timing.py,sha256=XrFUHIPT4EHDujLKbGs9fGFMmoM3NEP8xPRaESJr7bQ,1513
@@ -565,9 +566,10 @@ omlish/sockets/bind.py,sha256=J1SfFFFnVf3H5nqESDX2NGEY8DmjyIMUXZciZM33zQY,8003
565
566
  omlish/sockets/handlers.py,sha256=Gj6xZoo4vommge8XvkehYw3B7O4aql2P4qzZIIa0p24,462
566
567
  omlish/sockets/io.py,sha256=lfhTkB7NnAIx9kuQhAkwgsEUXY78Mp1_WtYrIQNS_k8,1408
567
568
  omlish/sockets/ports.py,sha256=Wm4mRFFz5MdD8KbdaEfT1c4PbJnsuK_iyJlZJE_-8jo,1402
569
+ omlish/sockets/wait.py,sha256=FSHzLR66RESMwHCV-Bu_mZWNNskRGfEwvM9q1arapV0,1049
568
570
  omlish/sockets/server/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
569
571
  omlish/sockets/server/handlers.py,sha256=PPsb1X5oU9dN8jfztaMGsRiqWTyEANT-1aSLbS6bUVg,3867
570
- omlish/sockets/server/server.py,sha256=mZmHPkCRPitous56_7FJdAsDLZag2wDqjj-LaYM8_Fg,4943
572
+ omlish/sockets/server/server.py,sha256=FkaishIxJuU4it9tTI7wzlGqJYzFGXzDrd_HgV0jAmU,6253
571
573
  omlish/sockets/server/ssl.py,sha256=VE0GpdA-gYsN2m9_uvfDwWmXtIbRQqJomVdpGJO8o2M,1061
572
574
  omlish/sockets/server/threading.py,sha256=YmW3Ym_p5j_F4SIH9BgRHIObywjq1HS39j9CGWIcMAY,2856
573
575
  omlish/specs/__init__.py,sha256=zZwF8yXTEkSstYtORkDhVLK-_hWU8WOJCuBpognb_NY,118
@@ -727,9 +729,9 @@ omlish/text/mangle.py,sha256=kfzFLfvepH-chl1P89_mdc5vC4FSqyPA2aVtgzuB8IY,1133
727
729
  omlish/text/minja.py,sha256=jZC-fp3Xuhx48ppqsf2Sf1pHbC0t8XBB7UpUUoOk2Qw,5751
728
730
  omlish/text/parts.py,sha256=JkNZpyR2tv2CNcTaWJJhpQ9E4F0yPR8P_YfDbZfMtwQ,6182
729
731
  omlish/text/random.py,sha256=jNWpqiaKjKyTdMXC-pWAsSC10AAP-cmRRPVhm59ZWLk,194
730
- omlish-0.0.0.dev242.dist-info/LICENSE,sha256=B_hVtavaA8zCYDW99DYdcpDLKz1n3BBRjZrcbv8uG8c,1451
731
- omlish-0.0.0.dev242.dist-info/METADATA,sha256=f11RfSbCLw8fvLQKc--nQePc_WBXEXJ_ljN3zB8QuvM,4176
732
- omlish-0.0.0.dev242.dist-info/WHEEL,sha256=jB7zZ3N9hIM9adW7qlTAyycLYW9npaWKLRzaoVcLKcM,91
733
- omlish-0.0.0.dev242.dist-info/entry_points.txt,sha256=Lt84WvRZJskWCAS7xnQGZIeVWksprtUHj0llrvVmod8,35
734
- omlish-0.0.0.dev242.dist-info/top_level.txt,sha256=pePsKdLu7DvtUiecdYXJ78iO80uDNmBlqe-8hOzOmfs,7
735
- omlish-0.0.0.dev242.dist-info/RECORD,,
732
+ omlish-0.0.0.dev243.dist-info/LICENSE,sha256=B_hVtavaA8zCYDW99DYdcpDLKz1n3BBRjZrcbv8uG8c,1451
733
+ omlish-0.0.0.dev243.dist-info/METADATA,sha256=dvum371m78Sb6B5v3K-C8hyOFzA8rEjIQUyy8GZH2G0,4176
734
+ omlish-0.0.0.dev243.dist-info/WHEEL,sha256=jB7zZ3N9hIM9adW7qlTAyycLYW9npaWKLRzaoVcLKcM,91
735
+ omlish-0.0.0.dev243.dist-info/entry_points.txt,sha256=Lt84WvRZJskWCAS7xnQGZIeVWksprtUHj0llrvVmod8,35
736
+ omlish-0.0.0.dev243.dist-info/top_level.txt,sha256=pePsKdLu7DvtUiecdYXJ78iO80uDNmBlqe-8hOzOmfs,7
737
+ omlish-0.0.0.dev243.dist-info/RECORD,,