omlish 0.0.0.dev21__py3-none-any.whl → 0.0.0.dev22__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.dev21'
2
- __revision__ = '4cb4af9e253f312d5f301449f08dfa7168234e07'
1
+ __version__ = '0.0.0.dev22'
2
+ __revision__ = '3d902899000237758f62e46319a8da3bccd2d447'
3
3
 
4
4
 
5
5
  #
@@ -33,10 +33,10 @@ class Project(ProjectBase):
33
33
  'anyio ~= 4.4',
34
34
  'sniffio ~= 1.3',
35
35
 
36
- 'greenlet ~= 3.0; python_version < "3.13"',
36
+ 'greenlet ~= 3.1',
37
37
 
38
38
  'trio ~= 0.26',
39
- 'trio-asyncio ~= 0.15; python_version < "3.13"',
39
+ 'trio-asyncio ~= 0.15',
40
40
  ],
41
41
 
42
42
  'compression': [
@@ -46,12 +46,15 @@ class Project(ProjectBase):
46
46
  ],
47
47
 
48
48
  'diag': [
49
+ 'asttokens ~= 2.4',
50
+ 'executing ~= 2.1',
51
+
49
52
  'psutil ~= 6.0',
50
53
  ],
51
54
 
52
55
  'formats': [
53
56
  'orjson ~= 3.10',
54
- # 'ujson ~= 5.10',
57
+ 'ujson ~= 5.10',
55
58
 
56
59
  'json5 ~= 0.9',
57
60
 
@@ -74,8 +77,7 @@ class Project(ProjectBase):
74
77
  ],
75
78
 
76
79
  'sql': [
77
- 'sqlalchemy ~= 2.0; python_version ~= "3.13"',
78
- 'sqlalchemy[asyncio] ~= 2.0; python_version < "3.13"',
80
+ 'sqlalchemy[asyncio] ~= 2.0',
79
81
 
80
82
  'pg8000 ~= 1.31',
81
83
  'pymysql ~= 1.1',
omlish/asyncs/bridge.py CHANGED
@@ -15,22 +15,21 @@ import types
15
15
  import typing as ta
16
16
  import weakref
17
17
 
18
+ from .. import check
18
19
  from .. import lang
20
+ from .. import sync
21
+ from ..concurrent import threadlets
19
22
  from .asyncs import sync_await
20
23
 
21
24
 
22
25
  if ta.TYPE_CHECKING:
23
26
  import asyncio
24
27
 
25
- import greenlet
26
-
27
28
  from . import anyio as aiu
28
29
 
29
30
  else:
30
31
  asyncio = lang.proxy_import('asyncio')
31
32
 
32
- greenlet = lang.proxy_import('greenlet')
33
-
34
33
  aiu = lang.proxy_import('.anyio', __package__)
35
34
 
36
35
 
@@ -56,6 +55,20 @@ def trivial_a_to_s(fn):
56
55
  # https://gist.github.com/snaury/202bf4f22c41ca34e56297bae5f33fef
57
56
 
58
57
 
58
+ _THREADLETS_IMPL = threadlets.GreenletThreadlets
59
+ # from ..concurrent.tests.real import RealThreadlets
60
+ # _THREADLETS_IMPL = RealThreadlets
61
+
62
+ _THREADLETS = sync.LazyFn(lambda: _THREADLETS_IMPL())
63
+
64
+
65
+ def _threadlets() -> threadlets.Threadlets:
66
+ return _THREADLETS.get()
67
+
68
+
69
+ #
70
+
71
+
59
72
  class BridgeAwaitRequiredError(Exception):
60
73
  pass
61
74
 
@@ -101,7 +114,7 @@ def _make_transition(seq: int, a_to_s: bool, obj: ta.Any) -> _BridgeTransition:
101
114
 
102
115
  _BRIDGED_TASKS: ta.MutableMapping[ta.Any, list[_BridgeTransition]] = weakref.WeakKeyDictionary()
103
116
 
104
- _BRIDGE_GREENLET_ATTR = f'__{__package__.replace(".", "__")}__bridge_greenlet__'
117
+ _BRIDGE_THREADLET_ATTR = f'__{__package__.replace(".", "__")}__bridge_threadlet__'
105
118
 
106
119
 
107
120
  def _push_transition(a_to_s: bool, l: list[_BridgeTransition], t: _BridgeTransition) -> _BridgeTransition:
@@ -129,9 +142,9 @@ def _get_transitions() -> list[_BridgeTransition]:
129
142
  else:
130
143
  l.extend(tl)
131
144
 
132
- g = greenlet.getcurrent()
145
+ g = _threadlets().get_current()
133
146
  try:
134
- gl = getattr(g, _BRIDGE_GREENLET_ATTR)
147
+ gl = getattr(g.underlying, _BRIDGE_THREADLET_ATTR)
135
148
  except AttributeError:
136
149
  pass
137
150
  else:
@@ -158,9 +171,9 @@ def is_in_bridge() -> bool:
158
171
  else:
159
172
  last_t = None
160
173
 
161
- g = greenlet.getcurrent()
174
+ g = _threadlets().get_current()
162
175
  try:
163
- gl = getattr(g, _BRIDGE_GREENLET_ATTR)
176
+ gl = getattr(g.underlying, _BRIDGE_THREADLET_ATTR)
164
177
  except AttributeError:
165
178
  last_g = None
166
179
  else:
@@ -194,13 +207,13 @@ def _safe_cancel_awaitable(awaitable: ta.Awaitable[ta.Any]) -> None:
194
207
 
195
208
 
196
209
  def s_to_a_await(awaitable: ta.Awaitable[T]) -> T:
197
- g = greenlet.getcurrent()
210
+ g = _threadlets().get_current()
198
211
 
199
- if not getattr(g, _BRIDGE_GREENLET_ATTR, False):
212
+ if not getattr(g.underlying, _BRIDGE_THREADLET_ATTR, False):
200
213
  _safe_cancel_awaitable(awaitable)
201
214
  raise MissingBridgeGreenletError
202
215
 
203
- return g.parent.switch(awaitable)
216
+ return check.not_none(g.parent).switch(awaitable)
204
217
 
205
218
 
206
219
  def s_to_a(fn, *, require_await=False):
@@ -210,7 +223,7 @@ def s_to_a(fn, *, require_await=False):
210
223
  try:
211
224
  return fn(*args, **kwargs)
212
225
  finally:
213
- if (gl2 := getattr(g, _BRIDGE_GREENLET_ATTR)) is not gl: # noqa
226
+ if (gl2 := getattr(g.underlying, _BRIDGE_THREADLET_ATTR)) is not gl: # noqa
214
227
  raise UnexpectedBridgeNestingError
215
228
  if (cur_g := _pop_transition(False, gl)) is not added_g: # noqa
216
229
  raise UnexpectedBridgeNestingError
@@ -219,8 +232,8 @@ def s_to_a(fn, *, require_await=False):
219
232
 
220
233
  seq = next(_BRIDGE_TRANSITIONS_SEQ)
221
234
 
222
- g = greenlet.greenlet(inner)
223
- setattr(g, _BRIDGE_GREENLET_ATTR, gl := []) # type: ignore
235
+ g = _threadlets().spawn(inner)
236
+ setattr(g.underlying, _BRIDGE_THREADLET_ATTR, gl := []) # type: ignore
224
237
  added_g = _push_transition(False, gl, _make_transition(seq, False, g))
225
238
 
226
239
  if (t := aiu.get_current_backend_task()) is not None:
@@ -270,11 +283,11 @@ def a_to_s(fn):
270
283
  else:
271
284
  added_t = None
272
285
 
273
- g = greenlet.getcurrent()
286
+ g = _threadlets().get_current()
274
287
  try:
275
- gl = getattr(g, _BRIDGE_GREENLET_ATTR)
288
+ gl = getattr(g.underlying, _BRIDGE_THREADLET_ATTR)
276
289
  except AttributeError:
277
- setattr(g, _BRIDGE_GREENLET_ATTR, gl := [])
290
+ setattr(g.underlying, _BRIDGE_THREADLET_ATTR, gl := [])
278
291
  added_g = _push_transition(True, gl, _make_transition(seq, True, g))
279
292
 
280
293
  try:
@@ -306,7 +319,7 @@ def a_to_s(fn):
306
319
  if (cur_t := _pop_transition(True, tl)) is not added_t: # noqa
307
320
  raise UnexpectedBridgeNestingError
308
321
 
309
- if (gl2 := getattr(g, _BRIDGE_GREENLET_ATTR)) is not gl: # noqa
322
+ if (gl2 := getattr(g.underlying, _BRIDGE_THREADLET_ATTR)) is not gl: # noqa
310
323
  raise UnexpectedBridgeNestingError
311
324
  if (cur_g := _pop_transition(True, gl)) is not added_g: # noqa
312
325
  raise UnexpectedBridgeNestingError
omlish/bootstrap/diag.py CHANGED
@@ -70,6 +70,7 @@ class ThreadDumpBootstrap(ContextBootstrap['ThreadDumpBootstrap.Config']):
70
70
  @dc.dataclass(frozen=True)
71
71
  class Config(Bootstrap.Config):
72
72
  interval_s: ta.Optional[float] = None
73
+ nodaemon: bool = False
73
74
 
74
75
  on_sigquit: bool = False
75
76
 
@@ -79,6 +80,7 @@ class ThreadDumpBootstrap(ContextBootstrap['ThreadDumpBootstrap.Config']):
79
80
  tdt = diagt.create_thread_dump_thread(
80
81
  interval_s=self._config.interval_s,
81
82
  start=True,
83
+ nodaemon=self._config.nodaemon,
82
84
  )
83
85
  else:
84
86
  tdt = None
@@ -97,7 +99,7 @@ class ThreadDumpBootstrap(ContextBootstrap['ThreadDumpBootstrap.Config']):
97
99
  yield
98
100
 
99
101
  finally:
100
- if tdt is not None:
102
+ if tdt is not None and not self._config.nodaemon:
101
103
  tdt.stop_nowait()
102
104
 
103
105
  if prev_sq.present:
@@ -0,0 +1,11 @@
1
+ from .executors import ( # noqa
2
+ ImmediateExecutor,
3
+ new_executor,
4
+ )
5
+
6
+ from .futures import ( # noqa
7
+ FutureError,
8
+ FutureTimeoutError,
9
+ wait_futures,
10
+ wait_dependent_futures,
11
+ )
@@ -0,0 +1,52 @@
1
+ import concurrent.futures as cf
2
+ import contextlib
3
+ import typing as ta
4
+
5
+
6
+ T = ta.TypeVar('T')
7
+ P = ta.ParamSpec('P')
8
+
9
+
10
+ class ImmediateExecutor(cf.Executor):
11
+
12
+ def __init__(self, *, immediate_exceptions: bool = False) -> None:
13
+ super().__init__()
14
+ self._immediate_exceptions = immediate_exceptions
15
+
16
+ def submit(
17
+ self,
18
+ fn: ta.Callable[P, T],
19
+ /,
20
+ *args: P.args,
21
+ **kwargs: P.kwargs,
22
+ ) -> cf.Future[T]:
23
+ future: ta.Any = cf.Future()
24
+ try:
25
+ result = fn(*args, **kwargs)
26
+ future.set_result(result)
27
+ except Exception as e:
28
+ if self._immediate_exceptions:
29
+ raise
30
+ future.set_exception(e)
31
+ return future
32
+
33
+
34
+ @contextlib.contextmanager
35
+ def new_executor(
36
+ max_workers: int | None = None,
37
+ cls: type[cf.Executor] = cf.ThreadPoolExecutor,
38
+ *,
39
+ immediate_exceptions: bool = False,
40
+ **kwargs: ta.Any,
41
+ ) -> ta.Generator[cf.Executor, None, None]:
42
+ if max_workers == 0:
43
+ yield ImmediateExecutor(
44
+ immediate_exceptions=immediate_exceptions,
45
+ )
46
+
47
+ else:
48
+ with cls( # type: ignore
49
+ max_workers,
50
+ **kwargs,
51
+ ) as exe:
52
+ yield exe
@@ -1,11 +1,9 @@
1
1
  import concurrent.futures as cf
2
- import contextlib
3
2
  import time
4
3
  import typing as ta
5
4
 
6
5
 
7
6
  T = ta.TypeVar('T')
8
- P = ta.ParamSpec('P')
9
7
 
10
8
 
11
9
  ##
@@ -137,45 +135,3 @@ def wait_dependent_futures(
137
135
 
138
136
  futs_by_fn = {fn: fut for fut, fn in fns_by_fut.items()}
139
137
  return futs_by_fn
140
-
141
-
142
- ##
143
-
144
-
145
- class ImmediateExecutor(cf.Executor):
146
-
147
- def __init__(self, *, immediate_exceptions: bool = False) -> None:
148
- super().__init__()
149
- self._immediate_exceptions = immediate_exceptions
150
-
151
- def submit(self, fn: ta.Callable[P, T], /, *args: P.args, **kwargs: P.kwargs) -> cf.Future[T]:
152
- future: ta.Any = cf.Future()
153
- try:
154
- result = fn(*args, **kwargs)
155
- future.set_result(result)
156
- except Exception as e:
157
- if self._immediate_exceptions:
158
- raise
159
- future.set_exception(e)
160
- return future
161
-
162
-
163
- @contextlib.contextmanager
164
- def new_executor(
165
- max_workers: int | None = None,
166
- cls: type[cf.Executor] = cf.ThreadPoolExecutor,
167
- *,
168
- immediate_exceptions: bool = False,
169
- **kwargs: ta.Any,
170
- ) -> ta.Generator[cf.Executor, None, None]:
171
- if max_workers == 0:
172
- yield ImmediateExecutor(
173
- immediate_exceptions=immediate_exceptions,
174
- )
175
-
176
- else:
177
- with cls( # type: ignore
178
- max_workers,
179
- **kwargs,
180
- ) as exe:
181
- yield exe
@@ -0,0 +1,91 @@
1
+ import abc
2
+ import dataclasses as dc
3
+ import typing as ta
4
+
5
+ from omlish import lang
6
+
7
+
8
+ if ta.TYPE_CHECKING:
9
+ import greenlet
10
+ else:
11
+ greenlet = lang.proxy_import('greenlet')
12
+
13
+
14
+ ##
15
+
16
+
17
+ class Threadlet(abc.ABC):
18
+ """Not safe to identity-key - use `underlying`."""
19
+
20
+ def __hash__(self):
21
+ raise TypeError('use `underlying`')
22
+
23
+ def __eq__(self, other):
24
+ raise TypeError('use `underlying`')
25
+
26
+ @property
27
+ @abc.abstractmethod
28
+ def underlying(self) -> ta.Any:
29
+ raise NotImplementedError
30
+
31
+ @property
32
+ @abc.abstractmethod
33
+ def parent(self) -> ta.Optional['Threadlet']:
34
+ raise NotImplementedError
35
+
36
+ @property
37
+ @abc.abstractmethod
38
+ def dead(self) -> bool:
39
+ raise NotImplementedError
40
+
41
+ @abc.abstractmethod
42
+ def switch(self, *args: ta.Any, **kwargs: ta.Any) -> ta.Any:
43
+ raise NotImplementedError
44
+
45
+ @abc.abstractmethod
46
+ def throw(self, ex: Exception) -> ta.Any:
47
+ raise NotImplementedError
48
+
49
+
50
+ class Threadlets(abc.ABC):
51
+ @abc.abstractmethod
52
+ def spawn(self, fn: ta.Callable[[], None]) -> Threadlet:
53
+ raise NotImplementedError
54
+
55
+ @abc.abstractmethod
56
+ def get_current(self) -> Threadlet:
57
+ raise NotImplementedError
58
+
59
+
60
+ ##
61
+
62
+
63
+ @dc.dataclass(frozen=True)
64
+ class GreenletThreadlet(Threadlet):
65
+ g: 'greenlet.greenlet'
66
+
67
+ @property
68
+ def underlying(self) -> 'greenlet.greenlet':
69
+ return self.g
70
+
71
+ @property
72
+ def parent(self) -> ta.Optional['GreenletThreadlet']:
73
+ return GreenletThreadlet(self.g.parent)
74
+
75
+ @property
76
+ def dead(self) -> bool:
77
+ return self.g.dead
78
+
79
+ def switch(self, *args: ta.Any, **kwargs: ta.Any) -> ta.Any:
80
+ return self.g.switch(*args, **kwargs)
81
+
82
+ def throw(self, ex: Exception) -> ta.Any:
83
+ return self.g.throw(ex)
84
+
85
+
86
+ class GreenletThreadlets(Threadlets):
87
+ def spawn(self, fn: ta.Callable[[], None]) -> Threadlet:
88
+ return GreenletThreadlet(greenlet.greenlet(fn))
89
+
90
+ def get_current(self) -> Threadlet:
91
+ return GreenletThreadlet(greenlet.getcurrent())
omlish/lang/functions.py CHANGED
@@ -108,6 +108,9 @@ def issubclass_of(class_or_tuple: ta.Any) -> ta.Callable[[ta.Any], bool]:
108
108
  return lambda o: issubclass(o, class_or_tuple)
109
109
 
110
110
 
111
+ ##
112
+
113
+
111
114
  class VoidError(Exception):
112
115
  pass
113
116
 
omlish/logs/__init__.py CHANGED
@@ -8,6 +8,10 @@ from .formatters import ( # noqa
8
8
  StandardLogFormatter,
9
9
  )
10
10
 
11
+ from .handlers import ( # noqa
12
+ ListHandler,
13
+ )
14
+
11
15
  from .utils import ( # noqa
12
16
  error_logging,
13
17
  )
@@ -0,0 +1,10 @@
1
+ import logging
2
+
3
+
4
+ class ListHandler(logging.Handler):
5
+ def __init__(self) -> None:
6
+ super().__init__()
7
+ self.records: list[logging.LogRecord] = []
8
+
9
+ def emit(self, record):
10
+ self.records.append(record)
omlish/secrets/openssl.py CHANGED
@@ -42,7 +42,7 @@ def generate_key(self, sz: int = DEFAULT_KEY_SIZE) -> bytes:
42
42
  ##
43
43
 
44
44
 
45
- class OpensslAes265CbcCrypto(Crypto):
45
+ class OpensslAescbcCrypto(Crypto):
46
46
  """
47
47
  !!! https://docs.openssl.org/3.0/man7/passphrase-encoding/
48
48
  https://cryptography.io/en/latest/hazmat/primitives/symmetric-encryption/#cryptography.hazmat.primitives.ciphers.Cipher
@@ -122,7 +122,7 @@ class OpensslAes265CbcCrypto(Crypto):
122
122
  ##
123
123
 
124
124
 
125
- class OpensslSubprocessAes256CbcCrypto(Crypto):
125
+ class OpensslSubprocessAescbcCrypto(Crypto):
126
126
  def __init__(
127
127
  self,
128
128
  *,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: omlish
3
- Version: 0.0.0.dev21
3
+ Version: 0.0.0.dev22
4
4
  Summary: omlish
5
5
  Author: wrmsr
6
6
  License: BSD-3-Clause
@@ -15,11 +15,16 @@ License-File: LICENSE
15
15
  Provides-Extra: all
16
16
  Requires-Dist: anyio ~=4.4 ; extra == 'all'
17
17
  Requires-Dist: sniffio ~=1.3 ; extra == 'all'
18
+ Requires-Dist: greenlet ~=3.1 ; extra == 'all'
18
19
  Requires-Dist: trio ~=0.26 ; extra == 'all'
20
+ Requires-Dist: trio-asyncio ~=0.15 ; extra == 'all'
19
21
  Requires-Dist: lz4 ~=4.0 ; extra == 'all'
20
22
  Requires-Dist: zstd ~=1.5 ; extra == 'all'
23
+ Requires-Dist: asttokens ~=2.4 ; extra == 'all'
24
+ Requires-Dist: executing ~=2.1 ; extra == 'all'
21
25
  Requires-Dist: psutil ~=6.0 ; extra == 'all'
22
26
  Requires-Dist: orjson ~=3.10 ; extra == 'all'
27
+ Requires-Dist: ujson ~=5.10 ; extra == 'all'
23
28
  Requires-Dist: json5 ~=0.9 ; extra == 'all'
24
29
  Requires-Dist: pyyaml ~=5.0 ; extra == 'all'
25
30
  Requires-Dist: cloudpickle ~=3.0 ; extra == 'all'
@@ -27,33 +32,33 @@ Requires-Dist: httpx[http2] ~=0.27 ; extra == 'all'
27
32
  Requires-Dist: jinja2 ~=3.1 ; extra == 'all'
28
33
  Requires-Dist: wrapt ~=1.14 ; extra == 'all'
29
34
  Requires-Dist: cryptography ~=43.0 ; extra == 'all'
35
+ Requires-Dist: sqlalchemy[asyncio] ~=2.0 ; extra == 'all'
30
36
  Requires-Dist: pg8000 ~=1.31 ; extra == 'all'
31
37
  Requires-Dist: pymysql ~=1.1 ; extra == 'all'
32
38
  Requires-Dist: aiomysql ~=0.2 ; extra == 'all'
33
39
  Requires-Dist: aiosqlite ~=0.20 ; extra == 'all'
34
40
  Requires-Dist: duckdb ~=1.1 ; extra == 'all'
35
41
  Requires-Dist: pytest ~=8.0 ; extra == 'all'
36
- Requires-Dist: greenlet ~=3.0 ; (python_version < "3.13") and extra == 'all'
37
- Requires-Dist: trio-asyncio ~=0.15 ; (python_version < "3.13") and extra == 'all'
38
42
  Requires-Dist: python-snappy ~=0.7 ; (python_version < "3.13") and extra == 'all'
39
- Requires-Dist: sqlalchemy[asyncio] ~=2.0 ; (python_version < "3.13") and extra == 'all'
40
43
  Requires-Dist: asyncpg ~=0.29 ; (python_version < "3.13") and extra == 'all'
41
44
  Requires-Dist: sqlean.py ~=3.45 ; (python_version < "3.13") and extra == 'all'
42
- Requires-Dist: sqlalchemy ~=2.0 ; (python_version ~= "3.13") and extra == 'all'
43
45
  Provides-Extra: async
44
46
  Requires-Dist: anyio ~=4.4 ; extra == 'async'
45
47
  Requires-Dist: sniffio ~=1.3 ; extra == 'async'
48
+ Requires-Dist: greenlet ~=3.1 ; extra == 'async'
46
49
  Requires-Dist: trio ~=0.26 ; extra == 'async'
47
- Requires-Dist: greenlet ~=3.0 ; (python_version < "3.13") and extra == 'async'
48
- Requires-Dist: trio-asyncio ~=0.15 ; (python_version < "3.13") and extra == 'async'
50
+ Requires-Dist: trio-asyncio ~=0.15 ; extra == 'async'
49
51
  Provides-Extra: compression
50
52
  Requires-Dist: lz4 ~=4.0 ; extra == 'compression'
51
53
  Requires-Dist: zstd ~=1.5 ; extra == 'compression'
52
54
  Requires-Dist: python-snappy ~=0.7 ; (python_version < "3.13") and extra == 'compression'
53
55
  Provides-Extra: diag
56
+ Requires-Dist: asttokens ~=2.4 ; extra == 'diag'
57
+ Requires-Dist: executing ~=2.1 ; extra == 'diag'
54
58
  Requires-Dist: psutil ~=6.0 ; extra == 'diag'
55
59
  Provides-Extra: formats
56
60
  Requires-Dist: orjson ~=3.10 ; extra == 'formats'
61
+ Requires-Dist: ujson ~=5.10 ; extra == 'formats'
57
62
  Requires-Dist: json5 ~=0.9 ; extra == 'formats'
58
63
  Requires-Dist: pyyaml ~=5.0 ; extra == 'formats'
59
64
  Requires-Dist: cloudpickle ~=3.0 ; extra == 'formats'
@@ -65,13 +70,12 @@ Requires-Dist: wrapt ~=1.14 ; extra == 'misc'
65
70
  Provides-Extra: secrets
66
71
  Requires-Dist: cryptography ~=43.0 ; extra == 'secrets'
67
72
  Provides-Extra: sql
73
+ Requires-Dist: sqlalchemy[asyncio] ~=2.0 ; extra == 'sql'
68
74
  Requires-Dist: pg8000 ~=1.31 ; extra == 'sql'
69
75
  Requires-Dist: pymysql ~=1.1 ; extra == 'sql'
70
76
  Requires-Dist: aiomysql ~=0.2 ; extra == 'sql'
71
77
  Requires-Dist: aiosqlite ~=0.20 ; extra == 'sql'
72
- Requires-Dist: sqlalchemy[asyncio] ~=2.0 ; (python_version < "3.13") and extra == 'sql'
73
78
  Requires-Dist: asyncpg ~=0.29 ; (python_version < "3.13") and extra == 'sql'
74
- Requires-Dist: sqlalchemy ~=2.0 ; (python_version ~= "3.13") and extra == 'sql'
75
79
  Provides-Extra: sqlx
76
80
  Requires-Dist: duckdb ~=1.1 ; extra == 'sqlx'
77
81
  Requires-Dist: sqlean.py ~=3.45 ; (python_version < "3.13") and extra == 'sqlx'
@@ -1,10 +1,9 @@
1
- omlish/__about__.py,sha256=EGrVhtPidloIZMlJKawKWjhmKU4ZCiYWFt2sk2YMU54,2451
1
+ omlish/__about__.py,sha256=V2bnCKc-3aJwdTP1xtp2ipVCaAqOuhGj6P8aqD-yHvs,2380
2
2
  omlish/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
3
  omlish/argparse.py,sha256=QRQmX9G0-L_nATkFtGHvpd4qrpYzKATdjuFLbBqzJPM,6224
4
4
  omlish/c3.py,sha256=W5EwYx9Por3rWYLkKUitJ6OoRMLLgVTfLTyroOz41Y0,8047
5
5
  omlish/cached.py,sha256=UAizxlH4eMWHPzQtmItmyE6FEpFEUFzIkxaO2BHWZ5s,196
6
6
  omlish/check.py,sha256=o3UJnIEmmRsv9ggIIDtz8fDSudW1CatxbwxP42M4dno,5543
7
- omlish/concurrent.py,sha256=jCGG76Ca_8761g1uY3nCJONg_Nxcf4JQQZYvvrmsKE4,5395
8
7
  omlish/datetimes.py,sha256=HajeM1kBvwlTa-uR1TTZHmZ3zTPnnUr1uGGQhiO1XQ0,2152
9
8
  omlish/defs.py,sha256=T3bq_7h_tO3nDB5RAFBn7DkdeQgqheXzkFColbOHZko,4890
10
9
  omlish/docker.py,sha256=5WyXJyFwqIJJ11QWwPIjHjDHnsaOVZszZAjyTvg3xew,4693
@@ -24,14 +23,14 @@ omlish/asyncs/__init__.py,sha256=uUz9ziKh4_QrgmdhKFMgq6j7mFbiZd3LiogguDCQsGI,587
24
23
  omlish/asyncs/anyio.py,sha256=Hqdi1iCopKoaAWGx-AYTRLEwnavLWx1esfJISK1IVF0,8024
25
24
  omlish/asyncs/asyncio.py,sha256=JfM59QgB3asgEbrps0zoVbNjWD4kL2XdsEkRMEIoFos,971
26
25
  omlish/asyncs/asyncs.py,sha256=Tf7ZodTGepkM7HAuFcDNh9lLzzrMw6rELWvopGmFkh4,2035
27
- omlish/asyncs/bridge.py,sha256=AabrRVz5k75dTB59M70DWkl6JrLusjhpvsaj5jld9io,8151
26
+ omlish/asyncs/bridge.py,sha256=dTVJrubiPlP0PlgJQT1Pj0jNDXFuPADtWymwSsgbl4k,8575
28
27
  omlish/asyncs/flavors.py,sha256=1mNxGNRVmjUHzA13K5ht8vdJv4CLEmzYTQ6BZXr1520,4866
29
28
  omlish/asyncs/trio.py,sha256=GKG3wgelFr7gIKKHZhcflvMyCvxXHNZe862KB0Xw2uA,370
30
29
  omlish/asyncs/trio_asyncio.py,sha256=oqdOHy0slj9PjVxaDf3gJkq9AAgg7wYZbB469jOftVw,1327
31
30
  omlish/bootstrap/__init__.py,sha256=Nii56mGsr1MsrQPQTX45kS6NsU0APK5t13Wlb1n8jlo,48
32
31
  omlish/bootstrap/__main__.py,sha256=d23loR_cKfTYZwYiqpt_CmKI7dd5WcYFgIYzqMep75E,68
33
32
  omlish/bootstrap/base.py,sha256=nyf2PYCoYzNEX_78Rm8szqpdTdhhSbSJEt3hf7OncvA,1032
34
- omlish/bootstrap/diag.py,sha256=TV4s3KcSvrDD0AK5Ggz7_rYMWbEK9_NfP3I0zf91m0o,2998
33
+ omlish/bootstrap/diag.py,sha256=BQf1MkhT-cY2vJGoSauOMZZagTc73tPV-NqmP5-AGWQ,3107
35
34
  omlish/bootstrap/harness.py,sha256=vQCIhCQY_N0NHWvDh8rG6Lo57U1qHkQf2egifbXzN-8,2027
36
35
  omlish/bootstrap/main.py,sha256=ZNzbT1t_dI4MhCB7so0glINw5XONTehIO5cv3hyXN44,5218
37
36
  omlish/bootstrap/sys.py,sha256=U0MFxO9tLFV3cdN5Y-Zrink6_45sFvzPUYQXyBk7-ns,8741
@@ -56,6 +55,10 @@ omlish/collections/cache/__init__.py,sha256=Cv8RX-Ehit3um0QLDq7uRDqJUCcdqTKoAB9T
56
55
  omlish/collections/cache/descriptor.py,sha256=t-1Gh4DTABDuNmeDJlpoW4LV3gi_uSlBd9ZfBINfYCM,5023
57
56
  omlish/collections/cache/impl.py,sha256=nQox5kChhns9h2a5gnX-ayQGBQJ5-B1aZkLQ2Aej19g,15137
58
57
  omlish/collections/cache/types.py,sha256=yNjwd6CGyTJQdxN2CQxFqqBAlcs1Z7vvNV-aU1K7p8E,685
58
+ omlish/concurrent/__init__.py,sha256=9p-s8MvBEYDqHIoYU3OYoe-Nni22QdkW7nhZGEukJTM,197
59
+ omlish/concurrent/executors.py,sha256=FYKCDYYuj-OgMa8quLsA47SfFNX3KDJvRENVk8NDsrA,1292
60
+ omlish/concurrent/futures.py,sha256=J2s9wYURUskqRJiBbAR0PNEAp1pXbIMYldOVBTQduQY,4239
61
+ omlish/concurrent/threadlets.py,sha256=2fzXEp_KPqIY7uoa5Jk2DJ3bLMY73ZsnzgN5myGanwc,2034
59
62
  omlish/configs/__init__.py,sha256=3uh09ezodTwkMI0nRmAMP0eEuJ_0VdF-LYyNmPjHiCE,77
60
63
  omlish/configs/classes.py,sha256=GLbB8xKjHjjoUQRCUQm3nEjM8z1qNTx9gPV7ODSt5dg,1317
61
64
  omlish/configs/flattening.py,sha256=AOlRpBHm449MxwMp3CiIRGunStOC1DUNs1f3CLou0wc,4731
@@ -161,7 +164,7 @@ omlish/lang/cmp.py,sha256=5vbzWWbqdzDmNKAGL19z6ZfUKe5Ci49e-Oegf9f4BsE,1346
161
164
  omlish/lang/contextmanagers.py,sha256=rzMSwJU7ObFXl46r6pGDbD45Zi_qZ9NHxDPnLNuux9o,9732
162
165
  omlish/lang/descriptors.py,sha256=VGbebrhWR0WLe3SASN444lBBvAreVMcwdam1FjcRxkQ,5908
163
166
  omlish/lang/exceptions.py,sha256=qJBo3NU1mOWWm-NhQUHCY5feYXR3arZVyEHinLsmRH4,47
164
- omlish/lang/functions.py,sha256=T4nPl46EHHGjMkz3FTRjsVhS9Y8HKcwM0jROU6_-Rv0,3619
167
+ omlish/lang/functions.py,sha256=yJxWwqlXEAT2gied4uTwiz5x1qXeuVubOSXyn9zy5aI,3624
165
168
  omlish/lang/imports.py,sha256=04ugFC8NI5sbL7NH4V0r0q_nFsP_AMkHLz697CVkMtQ,6274
166
169
  omlish/lang/iterables.py,sha256=_q6rHbdFfW3VBqez0IV3rUABoNxsA_oBv_sykm5zsbQ,2243
167
170
  omlish/lang/maybes.py,sha256=NYHZDjqDtwPMheDrj2VtUVujxRPf8Qpgk4ZlZCTvBZc,3492
@@ -196,10 +199,11 @@ omlish/lite/runtime.py,sha256=VUhmNQvwf8QzkWSKj4Q0ReieJA_PzHaJNRBivfTseow,452
196
199
  omlish/lite/secrets.py,sha256=FEc47dcU9M1CyMTnrihAAVwKf0ySZLahf83djOEDWXw,488
197
200
  omlish/lite/strings.py,sha256=9dO_A6EkhcTZ2xmOUGSOMT-mx9BnoOzYu1-ocSrDJaA,670
198
201
  omlish/lite/subprocesses.py,sha256=KuGV3ImehMjCUK0JoV3pUtG_7o5wei1lRDn9HxzByAg,3063
199
- omlish/logs/__init__.py,sha256=UPMdG3mbUm4PUJw6muXs4dk-uNE0aMDj_XebKCa-Wpk,224
202
+ omlish/logs/__init__.py,sha256=E4m-RTIaTh0rT9ADY9iB1Yc3pYBcnmn-tfkWXsjRTW4,276
200
203
  omlish/logs/_abc.py,sha256=UgrCUQVUi_PvT3p1CEkb3P74CFrFcZq2AFby3GEUv9M,5974
201
204
  omlish/logs/configs.py,sha256=VfZjhyA4CeMYNhlsv5oD2IZ6Iv4d_lbUgZzcnLAkxNA,1052
202
205
  omlish/logs/formatters.py,sha256=AFs9C6-qrFkgXZ0nL39wih_LGck1Tc79alvGyibBdQo,720
206
+ omlish/logs/handlers.py,sha256=nyuFgmO05By_Xwq7es58ClzS51-F53lJL7gD0x5IqAg,228
203
207
  omlish/logs/noisy.py,sha256=8JORjI1dH38yU2MddM54OB6qt32Xozfocdb88vY4wro,335
204
208
  omlish/logs/utils.py,sha256=MgGovbP0zUrZ3FGD3qYNQWn-l0jy0Y0bStcQvv5BOmQ,391
205
209
  omlish/marshal/__init__.py,sha256=Co5UUlCyd3eDToQTOvTURmCICKzuULnR5B6ylgb2nFM,1515
@@ -236,7 +240,7 @@ omlish/reflect/types.py,sha256=R9AH5YnOvdZs6QhzJ6VmjvcvGibQEQi6YqK25f5VUxw,6862
236
240
  omlish/secrets/__init__.py,sha256=VKB2IF9vz4h4RXcZxgXj36KXOLcGBzfqVnxPgPDWpmg,408
237
241
  omlish/secrets/crypto.py,sha256=6CsLy0UEqCrBK8Xx_3-iFF6SKtu2GlEqUQ8-MliY3tk,3709
238
242
  omlish/secrets/marshal.py,sha256=nVzsvQH5w3T2oMP7DCc1SLKxyR5e66psM57VOQoL0QA,2086
239
- omlish/secrets/openssl.py,sha256=nAA_wxk86G92B7027AoAlAiFliMjxLVs7xlaOAFGayE,6225
243
+ omlish/secrets/openssl.py,sha256=wxA_wIlxtuOUy71ABxAJgavh-UI_taOfm-A0dVlmSwM,6219
240
244
  omlish/secrets/passwords.py,sha256=3r-vEK6Gp6aq4L5Csnd06QnrjO9xfzHJP-g_7I9W_ao,4101
241
245
  omlish/secrets/secrets.py,sha256=hFN82uYiBVx8YSE86leWNxb4IRp3qdwZPOi4w04h8u0,6855
242
246
  omlish/secrets/subprocesses.py,sha256=EcnKlHHtnUMHGrBWXDfu8tv28wlgZx4P4GOiuPW9Vo8,1105
@@ -285,8 +289,8 @@ omlish/text/delimit.py,sha256=ubPXcXQmtbOVrUsNh5gH1mDq5H-n1y2R4cPL5_DQf68,4928
285
289
  omlish/text/glyphsplit.py,sha256=Ug-dPRO7x-OrNNr8g1y6DotSZ2KH0S-VcOmUobwa4B0,3296
286
290
  omlish/text/indent.py,sha256=6Jj6TFY9unaPa4xPzrnZemJ-fHsV53IamP93XGjSUHs,1274
287
291
  omlish/text/parts.py,sha256=KGgo0wHOIMVMZtDso-rhSWKAcAkYAH2IGpg9tULabu8,6505
288
- omlish-0.0.0.dev21.dist-info/LICENSE,sha256=B_hVtavaA8zCYDW99DYdcpDLKz1n3BBRjZrcbv8uG8c,1451
289
- omlish-0.0.0.dev21.dist-info/METADATA,sha256=xGxu7jRwygBxNlY-2GkuLO58zaPIx2lXCDxZg6N7GaI,3718
290
- omlish-0.0.0.dev21.dist-info/WHEEL,sha256=cVxcB9AmuTcXqmwrtPhNK88dr7IR_b6qagTj0UvIEbY,91
291
- omlish-0.0.0.dev21.dist-info/top_level.txt,sha256=pePsKdLu7DvtUiecdYXJ78iO80uDNmBlqe-8hOzOmfs,7
292
- omlish-0.0.0.dev21.dist-info/RECORD,,
292
+ omlish-0.0.0.dev22.dist-info/LICENSE,sha256=B_hVtavaA8zCYDW99DYdcpDLKz1n3BBRjZrcbv8uG8c,1451
293
+ omlish-0.0.0.dev22.dist-info/METADATA,sha256=VLYWv2M6zOnFd6tjfwCF6zxknpq4PAREgFChwcGrM-4,3666
294
+ omlish-0.0.0.dev22.dist-info/WHEEL,sha256=cVxcB9AmuTcXqmwrtPhNK88dr7IR_b6qagTj0UvIEbY,91
295
+ omlish-0.0.0.dev22.dist-info/top_level.txt,sha256=pePsKdLu7DvtUiecdYXJ78iO80uDNmBlqe-8hOzOmfs,7
296
+ omlish-0.0.0.dev22.dist-info/RECORD,,