omlish 0.0.0.dev28__py3-none-any.whl → 0.0.0.dev30__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.
Files changed (37) hide show
  1. omlish/__about__.py +7 -9
  2. omlish/collections/treap.py +0 -1
  3. omlish/dataclasses/impl/fields.py +3 -0
  4. omlish/diag/replserver/server.py +1 -1
  5. omlish/fnpipes.py +82 -0
  6. omlish/http/sessions.py +2 -2
  7. omlish/lang/__init__.py +6 -0
  8. omlish/lang/classes/abstract.py +1 -1
  9. omlish/lang/contextmanagers.py +35 -0
  10. omlish/lang/functions.py +17 -0
  11. omlish/lang/resources.py +1 -0
  12. omlish/lang/strings.py +49 -1
  13. omlish/lite/logs.py +20 -5
  14. omlish/lite/secrets.py +14 -0
  15. omlish/marshal/naming.py +5 -0
  16. omlish/marshal/polymorphism.py +20 -10
  17. omlish/math/__init__.py +0 -0
  18. omlish/{math.py → math/bits.py} +0 -13
  19. omlish/math/floats.py +13 -0
  20. omlish/{stats.py → math/stats.py} +3 -2
  21. omlish/os.py +17 -0
  22. omlish/specs/__init__.py +9 -0
  23. omlish/sql/__init__.py +0 -14
  24. omlish/sql/alchemy/__init__.py +13 -0
  25. omlish/sql/{asyncs.py → alchemy/asyncs.py} +1 -1
  26. omlish/sql/{duckdb.py → alchemy/duckdb.py} +1 -1
  27. omlish/sql/{secrets.py → alchemy/secrets.py} +1 -1
  28. omlish/testing/pytest/plugins/asyncs.py +5 -0
  29. omlish/text/asdl.py +5 -4
  30. omlish/text/parts.py +2 -2
  31. {omlish-0.0.0.dev28.dist-info → omlish-0.0.0.dev30.dist-info}/METADATA +17 -19
  32. {omlish-0.0.0.dev28.dist-info → omlish-0.0.0.dev30.dist-info}/RECORD +37 -33
  33. /omlish/sql/{exprs.py → alchemy/exprs.py} +0 -0
  34. /omlish/sql/{sqlean.py → alchemy/sqlean.py} +0 -0
  35. {omlish-0.0.0.dev28.dist-info → omlish-0.0.0.dev30.dist-info}/LICENSE +0 -0
  36. {omlish-0.0.0.dev28.dist-info → omlish-0.0.0.dev30.dist-info}/WHEEL +0 -0
  37. {omlish-0.0.0.dev28.dist-info → omlish-0.0.0.dev30.dist-info}/top_level.txt +0 -0
omlish/__about__.py CHANGED
@@ -1,5 +1,5 @@
1
- __version__ = '0.0.0.dev28'
2
- __revision__ = '8adf3c1230237633abb8801258638f0ae2fa4099'
1
+ __version__ = '0.0.0.dev30'
2
+ __revision__ = '1378b0a61f7d3ec16204c06bc87e5215b062d378'
3
3
 
4
4
 
5
5
  #
@@ -30,7 +30,7 @@ class Project(ProjectBase):
30
30
 
31
31
  optional_dependencies = {
32
32
  'async': [
33
- 'anyio ~= 4.4',
33
+ 'anyio ~= 4.5',
34
34
  'sniffio ~= 1.3',
35
35
 
36
36
  'greenlet ~= 3.1',
@@ -39,7 +39,7 @@ class Project(ProjectBase):
39
39
  'trio-asyncio ~= 0.15',
40
40
  ],
41
41
 
42
- 'compression': [
42
+ 'compress': [
43
43
  'lz4 ~= 4.0',
44
44
 
45
45
  'python-snappy ~= 0.7; python_version < "3.13"',
@@ -70,8 +70,6 @@ class Project(ProjectBase):
70
70
  ],
71
71
 
72
72
  'misc': [
73
- 'jinja2 ~= 3.1',
74
-
75
73
  'wrapt ~= 1.14',
76
74
  ],
77
75
 
@@ -79,9 +77,11 @@ class Project(ProjectBase):
79
77
  'cryptography ~= 43.0',
80
78
  ],
81
79
 
82
- 'sql': [
80
+ 'sqlalchemy': [
83
81
  'sqlalchemy[asyncio] ~= 2.0',
82
+ ],
84
83
 
84
+ 'sqlalchemy-drivers': [
85
85
  'pg8000 ~= 1.31',
86
86
  # 'psycopg2 ~= 2.9',
87
87
  # 'psycopg ~= 3.2',
@@ -93,9 +93,7 @@ class Project(ProjectBase):
93
93
  'aiomysql ~= 0.2',
94
94
  'aiosqlite ~= 0.20',
95
95
  'asyncpg ~= 0.29; python_version < "3.13"',
96
- ],
97
96
 
98
- 'sqlx': [
99
97
  'sqlean.py ~= 3.45; python_version < "3.13"',
100
98
 
101
99
  'duckdb ~= 1.1',
@@ -17,7 +17,6 @@ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER I
17
17
  OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
18
18
  """
19
19
  # ruff: noqa: SLF001
20
-
21
20
  import typing as ta
22
21
 
23
22
 
@@ -178,6 +178,9 @@ def field_init(
178
178
  if fx.derive is not None:
179
179
  raise NotImplementedError
180
180
 
181
+ if fx.frozen:
182
+ raise NotImplementedError
183
+
181
184
  if fx.coerce is not None:
182
185
  cn = f'__dataclass_coerce__{f.name}__'
183
186
  locals[cn] = fx.coerce
@@ -9,7 +9,7 @@ TODO:
9
9
  - optional ipython embed
10
10
  - https://github.com/python/cpython/tree/56470004e58911b146c016fc9fec4461b8f69454/Lib/_pyrepl
11
11
 
12
- lookit:
12
+ See:
13
13
  - https://github.com/vxgmichel/aioconsole/blob/e55f4b0601da3b3a40a88c965526d35ab38b5841/aioconsole/server.py
14
14
  - https://github.com/nhoad/aiomanhole
15
15
  - https://github.com/twisted/twisted/blob/00aa56f5257060304d41f09651c6ab58ee6104d6/src/twisted/conch/manhole.py
omlish/fnpipes.py ADDED
@@ -0,0 +1,82 @@
1
+ import abc
2
+ import typing as ta
3
+
4
+
5
+ T = ta.TypeVar('T')
6
+ U = ta.TypeVar('U')
7
+
8
+
9
+ class Fn(abc.ABC, ta.Generic[T]):
10
+ @abc.abstractmethod
11
+ def __call__(self, *args: ta.Any, **kwargs: ta.Any) -> T:
12
+ raise NotImplementedError
13
+
14
+ def pipe(self, fn: ta.Callable[..., U], *args: ta.Any, **kwargs: ta.Any) -> 'Fn[U]':
15
+ return Pipe([self], Bind(fn, *args, **kwargs))
16
+
17
+ def __or__(self, fn: ta.Callable[..., U]) -> 'Fn[U]':
18
+ return self.pipe(fn)
19
+
20
+ def apply(self, fn: ta.Callable[[T], ta.Any], *args: ta.Any, **kwargs: ta.Any) -> 'Fn[T]':
21
+ return Pipe([self], Apply(Bind(fn, *args, **kwargs)))
22
+
23
+ def __and__(self, fn: ta.Callable[[T], ta.Any]) -> 'Fn[T]':
24
+ return self.apply(fn)
25
+
26
+
27
+ class Bind(Fn[T]):
28
+ def __init__(self, fn: ta.Callable[..., T], *args: ta.Any, **kwargs: ta.Any) -> None:
29
+ super().__init__()
30
+ if Ellipsis not in args and Ellipsis not in kwargs:
31
+ args += (Ellipsis,)
32
+ self._fn = fn
33
+ self._args = args
34
+ self._kwargs = kwargs
35
+
36
+ def __call__(self, *args: ta.Any, **kwargs: ta.Any) -> T:
37
+ fa: list = []
38
+ for a in self._args:
39
+ if a is Ellipsis:
40
+ fa.extend(args)
41
+ else:
42
+ fa.append(a)
43
+
44
+ fkw = {}
45
+ for k, v in self._kwargs.items():
46
+ if v is Ellipsis:
47
+ if len(args) != 1:
48
+ raise ValueError(args)
49
+ fkw[k] = args[0]
50
+ else:
51
+ fkw[k] = v
52
+ fkw.update(kwargs)
53
+
54
+ return self._fn(*fa, **fkw)
55
+
56
+
57
+ class Pipe(Fn[T]):
58
+ def __init__(self, lfns: ta.Sequence[ta.Callable], rfn: ta.Callable[..., T]) -> None:
59
+ super().__init__()
60
+ self._lfn, *self._rfns = [*lfns, rfn]
61
+
62
+ def __call__(self, *args: ta.Any, **kwargs: ta.Any) -> T:
63
+ o = self._lfn(*args, **kwargs)
64
+ for fn in self._rfns:
65
+ o = fn(o)
66
+ return o
67
+
68
+
69
+ class Apply(Fn[T]):
70
+ def __init__(self, *fns: ta.Callable[[T], ta.Any]) -> None:
71
+ super().__init__()
72
+ self._fns = fns
73
+
74
+ def __call__(self, o: T) -> T: # noqa
75
+ for fn in self._fns:
76
+ fn(o)
77
+ return o
78
+
79
+
80
+ bind = Bind
81
+ pipe = Pipe
82
+ apply = Apply
omlish/http/sessions.py CHANGED
@@ -8,7 +8,7 @@ import time
8
8
  import typing as ta
9
9
  import zlib
10
10
 
11
- from .. import fnpairs as fps
11
+ from .. import fnpairs as fpa
12
12
  from .. import lang
13
13
  from .. import secrets as sec
14
14
  from .cookies import dump_cookie
@@ -92,7 +92,7 @@ class SessionMarshal:
92
92
  def __init__(
93
93
  self,
94
94
  signer: Signer,
95
- serializer: fps.ObjectStr = fps.of(JSON_TAGGER.dumps, JSON_TAGGER.loads),
95
+ serializer: fpa.ObjectStr = fpa.of(JSON_TAGGER.dumps, JSON_TAGGER.loads),
96
96
  ) -> None:
97
97
  super().__init__()
98
98
 
omlish/lang/__init__.py CHANGED
@@ -60,6 +60,7 @@ from .contextmanagers import ( # noqa
60
60
  NOP_CONTEXT_MANAGER,
61
61
  NopContextManaged,
62
62
  NopContextManager,
63
+ Timer,
63
64
  a_defer,
64
65
  attr_setting,
65
66
  breakpoint_on_exception,
@@ -98,6 +99,7 @@ from .functions import ( # noqa
98
99
  Args,
99
100
  VoidError,
100
101
  as_async,
102
+ coalesce,
101
103
  constant,
102
104
  finally_,
103
105
  identity,
@@ -107,6 +109,7 @@ from .functions import ( # noqa
107
109
  isinstance_of,
108
110
  issubclass_of,
109
111
  maybe_call,
112
+ opt_coalesce,
110
113
  periodically,
111
114
  raise_,
112
115
  raising,
@@ -186,8 +189,11 @@ from .strings import ( # noqa
186
189
  is_ident_cont,
187
190
  is_ident_start,
188
191
  is_sunder,
192
+ prefix_delimited,
189
193
  prefix_lines,
190
194
  snake_case,
195
+ strip_prefix,
196
+ strip_suffix,
191
197
  )
192
198
 
193
199
  from .sys import ( # noqa
@@ -47,7 +47,7 @@ class Abstract(abc.ABC): # noqa
47
47
  seen.update(dir(b))
48
48
  if ams:
49
49
  raise TypeError(
50
- f'Cannot subclass abstract class {cls.__name__} with abstract methods'
50
+ f'Cannot subclass abstract class {cls.__name__} with abstract methods: '
51
51
  f'{", ".join(map(str, sorted(ams)))}',
52
52
  )
53
53
 
@@ -7,6 +7,7 @@ import contextlib
7
7
  import contextvars
8
8
  import functools
9
9
  import threading
10
+ import time
10
11
  import types
11
12
  import typing as ta
12
13
 
@@ -367,3 +368,37 @@ def default_lock(value: DefaultLockable, default: DefaultLockable = None) -> Loc
367
368
 
368
369
  else:
369
370
  raise TypeError(value)
371
+
372
+
373
+ ##
374
+
375
+
376
+ class Timer:
377
+ def __init__(
378
+ self,
379
+ clock: ta.Callable[[], float] | None = None,
380
+ ) -> None:
381
+ super().__init__()
382
+ self._clock = clock if clock is not None else time.monotonic
383
+
384
+ _start: float
385
+ _end: float
386
+
387
+ @property
388
+ def start(self) -> float:
389
+ return self._start
390
+
391
+ @property
392
+ def end(self) -> float:
393
+ return self._end
394
+
395
+ @property
396
+ def elapsed(self) -> float:
397
+ return self._end - self._start
398
+
399
+ def __enter__(self) -> ta.Self:
400
+ self._start = self._clock()
401
+ return self
402
+
403
+ def __exit__(self, exc_type, exc_val, exc_tb):
404
+ self._end = self._clock()
omlish/lang/functions.py CHANGED
@@ -183,3 +183,20 @@ class Args:
183
183
 
184
184
  def __call__(self, fn: ta.Callable[..., T]) -> T:
185
185
  return fn(*self.args, **self.kwargs)
186
+
187
+
188
+ ##
189
+
190
+
191
+ def coalesce(*vs: T | None) -> T:
192
+ for v in vs:
193
+ if v is not None:
194
+ return v
195
+ raise ValueError('No value given')
196
+
197
+
198
+ def opt_coalesce(*vs: T | None) -> T | None:
199
+ for v in vs:
200
+ if v is not None:
201
+ return v
202
+ return None
omlish/lang/resources.py CHANGED
@@ -27,6 +27,7 @@ def get_relative_resources(
27
27
 
28
28
  if os.sep in path:
29
29
  raise ValueError(path) # noqa
30
+
30
31
  if not path.startswith('.'):
31
32
  path = '.' + path
32
33
  if set(path) - {'.'}:
omlish/lang/strings.py CHANGED
@@ -4,9 +4,22 @@ import unicodedata
4
4
 
5
5
  ##
6
6
 
7
+ @ta.overload
8
+ def prefix_delimited(s: str, p: str, d: str) -> str:
9
+ ...
10
+
11
+
12
+ @ta.overload
13
+ def prefix_delimited(s: bytes, p: bytes, d: bytes) -> bytes:
14
+ ...
15
+
16
+
17
+ def prefix_delimited(s, p, d):
18
+ return d.join([p + l for l in s.split(d)])
19
+
7
20
 
8
21
  def prefix_lines(s: str, p: str) -> str:
9
- return '\n'.join([p + l for l in s.split('\n')])
22
+ return prefix_delimited(s, p, '\n')
10
23
 
11
24
 
12
25
  def indent_lines(s: str, num: int) -> str:
@@ -16,6 +29,41 @@ def indent_lines(s: str, num: int) -> str:
16
29
  ##
17
30
 
18
31
 
32
+ @ta.overload
33
+ def strip_prefix(s: str, pfx: str) -> str:
34
+ ...
35
+
36
+
37
+ @ta.overload
38
+ def strip_prefix(s: bytes, pfx: bytes) -> bytes:
39
+ ...
40
+
41
+
42
+ def strip_prefix(s, pfx):
43
+ if not s.startswith(pfx):
44
+ raise ValueError(f'{s!r} does not start with {pfx!r}')
45
+ return s[len(pfx):]
46
+
47
+
48
+ @ta.overload
49
+ def strip_suffix(s: str, sfx: str) -> str:
50
+ ...
51
+
52
+
53
+ @ta.overload
54
+ def strip_suffix(s: bytes, sfx: bytes) -> bytes:
55
+ ...
56
+
57
+
58
+ def strip_suffix(s, sfx):
59
+ if not s.endswith(sfx):
60
+ raise ValueError(f'{s!r} does not end with {sfx!r}')
61
+ return s[:-len(sfx)]
62
+
63
+
64
+ ##
65
+
66
+
19
67
  def camel_case(name: str) -> str:
20
68
  return ''.join(map(str.capitalize, name.split('_'))) # noqa
21
69
 
omlish/lite/logs.py CHANGED
@@ -4,6 +4,7 @@ TODO:
4
4
  - debug
5
5
  """
6
6
  # ruff: noqa: UP006 UP007 N802
7
+ import contextlib
7
8
  import datetime
8
9
  import logging
9
10
  import threading
@@ -203,6 +204,24 @@ class StandardLogHandler(ProxyLogHandler):
203
204
  ##
204
205
 
205
206
 
207
+ @contextlib.contextmanager
208
+ def _locking_logging_module_lock() -> ta.Iterator[None]:
209
+ if hasattr(logging, '_acquireLock'):
210
+ logging._acquireLock() # noqa
211
+ try:
212
+ yield
213
+ finally:
214
+ logging._releaseLock() # type: ignore # noqa
215
+
216
+ elif hasattr(logging, '_lock'):
217
+ # https://github.com/python/cpython/commit/74723e11109a320e628898817ab449b3dad9ee96
218
+ with logging._lock: # noqa
219
+ yield
220
+
221
+ else:
222
+ raise Exception("Can't find lock in logging module")
223
+
224
+
206
225
  def configure_standard_logging(
207
226
  level: ta.Union[int, str] = logging.INFO,
208
227
  *,
@@ -210,8 +229,7 @@ def configure_standard_logging(
210
229
  target: ta.Optional[logging.Logger] = None,
211
230
  force: bool = False,
212
231
  ) -> ta.Optional[StandardLogHandler]:
213
- logging._acquireLock() # type: ignore # noqa
214
- try:
232
+ with _locking_logging_module_lock():
215
233
  if target is None:
216
234
  target = logging.root
217
235
 
@@ -250,6 +268,3 @@ def configure_standard_logging(
250
268
  #
251
269
 
252
270
  return StandardLogHandler(handler)
253
-
254
- finally:
255
- logging._releaseLock() # type: ignore # noqa
omlish/lite/secrets.py CHANGED
@@ -20,3 +20,17 @@ class Secret:
20
20
 
21
21
  def reveal(self) -> str:
22
22
  return getattr(self, self._VALUE_ATTR)()
23
+
24
+ #
25
+
26
+ def __reduce__(self) -> ta.NoReturn:
27
+ raise TypeError
28
+
29
+ def __reduce_ex__(self, protocol) -> ta.NoReturn:
30
+ raise TypeError
31
+
32
+ def __getstate__(self) -> ta.NoReturn:
33
+ raise TypeError
34
+
35
+ def __setstate__(self, state) -> ta.NoReturn:
36
+ raise TypeError
omlish/marshal/naming.py CHANGED
@@ -1,3 +1,8 @@
1
+ """
2
+ TODO:
3
+ - Namer: ta.TypeAlias = ta.Callable[[str], str] ?
4
+ - this interface is ~intentionally~ limited, but custom overrides would be useful
5
+ """
1
6
  import enum
2
7
 
3
8
  from .. import lang
@@ -98,24 +98,34 @@ def polymorphism_from_subclasses(
98
98
  ty: type,
99
99
  *,
100
100
  naming: Naming | None = None,
101
+ strip_suffix: bool = False,
101
102
  ) -> Polymorphism:
102
103
  dct: dict[str, Impl] = {}
104
+
103
105
  seen: set[type] = set()
104
106
  todo: list[type] = [ty]
105
107
  while todo:
106
108
  cur = todo.pop()
107
109
  seen.add(cur)
108
- if not lang.is_abstract_class(cur):
109
- nam = cur.__name__
110
- if naming is not None:
111
- nam = translate_name(nam, naming)
112
- if nam in dct:
113
- raise KeyError(f'Duplicate name: {nam}')
114
- dct[nam] = Impl(
115
- cur,
116
- nam,
117
- )
110
+
118
111
  todo.extend(nxt for nxt in cur.__subclasses__() if nxt not in seen)
112
+
113
+ if lang.is_abstract_class(cur):
114
+ continue
115
+
116
+ name = cur.__name__
117
+ if strip_suffix:
118
+ name = lang.strip_suffix(name, ty.__name__)
119
+ if naming is not None:
120
+ name = translate_name(name, naming)
121
+ if name in dct:
122
+ raise KeyError(f'Duplicate name: {name}')
123
+
124
+ dct[name] = Impl(
125
+ cur,
126
+ name,
127
+ )
128
+
119
129
  return Polymorphism(ty, dct.values())
120
130
 
121
131
 
File without changes
@@ -1,15 +1,10 @@
1
1
  import functools
2
- import struct
3
2
  import typing as ta
4
3
 
5
4
 
6
5
  ##
7
6
 
8
7
 
9
- def isclose(a: float, b: float, *, rel_tol: float = 1e-09, abs_tol: float = 0.0) -> float:
10
- return abs(a - b) <= max(rel_tol * max(abs(a), abs(b)), abs_tol)
11
-
12
-
13
8
  def get_bit(bit: int, value: int) -> int:
14
9
  return (value >> bit) & 1
15
10
 
@@ -29,14 +24,6 @@ def set_bits(bits_from: int, num_bits: int, bits_value: int, value: int) -> int:
29
24
  return value & ~(((1 << num_bits) - 1) << bits_from) | (bits_value << bits_from)
30
25
 
31
26
 
32
- def float_to_bytes(f: float) -> bytes:
33
- return struct.pack('>f', f)
34
-
35
-
36
- def bytes_to_float(b: bytes) -> float:
37
- return struct.unpack('>f', b)[0]
38
-
39
-
40
27
  ##
41
28
 
42
29
 
omlish/math/floats.py ADDED
@@ -0,0 +1,13 @@
1
+ import struct
2
+
3
+
4
+ def isclose(a: float, b: float, *, rel_tol: float = 1e-09, abs_tol: float = 0.0) -> float:
5
+ return abs(a - b) <= max(rel_tol * max(abs(a), abs(b)), abs_tol)
6
+
7
+
8
+ def float_to_bytes(f: float) -> bytes:
9
+ return struct.pack('>f', f)
10
+
11
+
12
+ def bytes_to_float(b: bytes) -> float:
13
+ return struct.unpack('>f', b)[0]
@@ -3,6 +3,7 @@ TODO:
3
3
  - reservoir
4
4
  - dep tdigest?
5
5
  - struct-of-arrays - array.array('f', ...) - backed SamplingHistogram
6
+ - https://docs.python.org/3/library/statistics.html
6
7
  """
7
8
  import bisect
8
9
  import collections
@@ -14,8 +15,8 @@ import random
14
15
  import time
15
16
  import typing as ta
16
17
 
17
- from . import cached
18
- from . import check
18
+ from .. import cached
19
+ from .. import check
19
20
 
20
21
 
21
22
  ##
omlish/os.py CHANGED
@@ -103,3 +103,20 @@ class Pidfile:
103
103
  def kill(self, sig: int = signal.SIGTERM) -> None:
104
104
  pid = self.read()
105
105
  os.kill(pid, sig) # Still racy
106
+
107
+
108
+ def touch(self, mode: int = 0o666, exist_ok: bool = True) -> None:
109
+ if exist_ok:
110
+ # First try to bump modification time
111
+ # Implementation note: GNU touch uses the UTIME_NOW option of the utimensat() / futimens() functions.
112
+ try:
113
+ os.utime(self, None)
114
+ except OSError:
115
+ pass
116
+ else:
117
+ return
118
+ flags = os.O_CREAT | os.O_WRONLY
119
+ if not exist_ok:
120
+ flags |= os.O_EXCL
121
+ fd = os.open(self, flags, mode)
122
+ os.close(fd)
omlish/specs/__init__.py CHANGED
@@ -0,0 +1,9 @@
1
+ """
2
+ TODO:
3
+ - avro
4
+ - jmespath
5
+ - jsonpatch
6
+ - jsonpointer.py
7
+ - openapi
8
+ - protobuf
9
+ """
omlish/sql/__init__.py CHANGED
@@ -1,13 +1,3 @@
1
- from .asyncs import ( # noqa
2
- AsyncConnection,
3
- AsyncConnectionLike,
4
- AsyncEngine,
5
- AsyncEngineLike,
6
- AsyncTransaction,
7
- AsyncTransactionLike,
8
- async_adapt,
9
- )
10
-
11
1
  from .dbs import ( # noqa
12
2
  DbLoc,
13
3
  DbSpec,
@@ -17,10 +7,6 @@ from .dbs import ( # noqa
17
7
  UrlDbLoc,
18
8
  )
19
9
 
20
- from .exprs import ( # noqa
21
- paren,
22
- )
23
-
24
10
  from .qualifiedname import ( # noqa
25
11
  QualifiedName,
26
12
  qn,
@@ -0,0 +1,13 @@
1
+ from .asyncs import ( # noqa
2
+ AsyncConnection,
3
+ AsyncConnectionLike,
4
+ AsyncEngine,
5
+ AsyncEngineLike,
6
+ AsyncTransaction,
7
+ AsyncTransactionLike,
8
+ async_adapt,
9
+ )
10
+
11
+ from .exprs import ( # noqa
12
+ paren,
13
+ )
@@ -9,7 +9,7 @@ import typing as ta
9
9
  import sqlalchemy as sa
10
10
  import sqlalchemy.ext.asyncio as saa
11
11
 
12
- from .. import asyncs as au
12
+ from ... import asyncs as au
13
13
 
14
14
 
15
15
  T = ta.TypeVar('T')
@@ -8,7 +8,7 @@ import typing as ta
8
8
  import sqlalchemy as sa
9
9
  from sqlalchemy.dialects import postgresql as sap
10
10
 
11
- from .. import lang
11
+ from ... import lang
12
12
 
13
13
 
14
14
  if ta.TYPE_CHECKING:
@@ -2,7 +2,7 @@
2
2
  TODO:
3
3
  - sync/async...
4
4
  """
5
- from .. import secrets as sec
5
+ from ... import secrets as sec
6
6
 
7
7
 
8
8
  class SqlFunctionSecrets(sec.Secrets):
@@ -111,6 +111,11 @@ class AsyncsPlugin:
111
111
  else:
112
112
  return
113
113
 
114
+ if 'trio_asyncio' in bes:
115
+ # NOTE: Importing it here is apparently necessary to get its patching working - otherwise fails later with
116
+ # `no running event loop` in anyio._backends._asyncio and such.
117
+ import trio_asyncio # noqa
118
+
114
119
  if pdu.is_present():
115
120
  pdu.patch_for_trio_asyncio()
116
121
 
omlish/text/asdl.py CHANGED
@@ -217,7 +217,7 @@ class TokenKind(enum.IntEnum):
217
217
  COMMA = enum.auto()
218
218
  QUESTION = enum.auto()
219
219
  PIPE = enum.auto()
220
- AstERISK = enum.auto()
220
+ ASTERISK = enum.auto()
221
221
  L_PAREN = enum.auto()
222
222
  R_PAREN = enum.auto()
223
223
  L_BRACE = enum.auto()
@@ -231,7 +231,7 @@ OPERATOR_TABLE: ta.Mapping[str, TokenKind] = {
231
231
  '|': TokenKind.PIPE,
232
232
  '(': TokenKind.L_PAREN,
233
233
  ')': TokenKind.R_PAREN,
234
- '*': TokenKind.AstERISK,
234
+ '*': TokenKind.ASTERISK,
235
235
  '{': TokenKind.L_BRACE,
236
236
  '}': TokenKind.R_BRACE,
237
237
  }
@@ -373,7 +373,7 @@ class AsdlParser:
373
373
 
374
374
  def _parse_optional_field_quantifier(self) -> tuple[bool, bool]: # (seq, opt)
375
375
  is_seq, is_opt = False, False
376
- if self.cur().kind == TokenKind.AstERISK:
376
+ if self.cur().kind == TokenKind.ASTERISK:
377
377
  is_seq = True
378
378
  self._advance()
379
379
  elif self.cur().kind == TokenKind.QUESTION:
@@ -394,7 +394,8 @@ class AsdlParser:
394
394
  _id_kinds = (TokenKind.CONSTRUCTOR_ID, TokenKind.TYPE_ID)
395
395
 
396
396
  def _match(self, kind: TokenKind | tuple[TokenKind, ...]) -> str:
397
- """The 'match' primitive of RD parsers.
397
+ """
398
+ The 'match' primitive of RD parsers.
398
399
 
399
400
  * Verifies that the current token is of the given kind (kind can be a tuple, in which the kind must match one of
400
401
  its members).
omlish/text/parts.py CHANGED
@@ -30,7 +30,7 @@ def _check_part(o: PartT) -> PartT:
30
30
  return o
31
31
 
32
32
 
33
- def _check_optional_part(o: PartT | None) -> PartT | None:
33
+ def _check_opt_part(o: PartT | None) -> PartT | None:
34
34
  if o is None:
35
35
  return None
36
36
  return _check_part(o)
@@ -49,7 +49,7 @@ class Wrap(DataPart, lang.Final):
49
49
 
50
50
 
51
51
  class List(DataPart, lang.Final):
52
- parts: ta.Sequence[Part | None] = dc.xfield(coerce=col.seq_of(_check_optional_part))
52
+ parts: ta.Sequence[Part | None] = dc.xfield(coerce=col.seq_of(_check_opt_part))
53
53
  delimiter: str = dc.field(default=',') # FIXME: , check_type=str)
54
54
  trailer: bool = dc.field(default=False) # FIXME: , check_type=bool)
55
55
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: omlish
3
- Version: 0.0.0.dev28
3
+ Version: 0.0.0.dev30
4
4
  Summary: omlish
5
5
  Author: wrmsr
6
6
  License: BSD-3-Clause
@@ -13,7 +13,7 @@ Classifier: Operating System :: POSIX
13
13
  Requires-Python: ~=3.12
14
14
  License-File: LICENSE
15
15
  Provides-Extra: all
16
- Requires-Dist: anyio ~=4.4 ; extra == 'all'
16
+ Requires-Dist: anyio ~=4.5 ; extra == 'all'
17
17
  Requires-Dist: sniffio ~=1.3 ; extra == 'all'
18
18
  Requires-Dist: greenlet ~=3.1 ; extra == 'all'
19
19
  Requires-Dist: trio ~=0.26 ; extra == 'all'
@@ -29,7 +29,6 @@ Requires-Dist: json5 ~=0.9 ; extra == 'all'
29
29
  Requires-Dist: pyyaml ~=5.0 ; extra == 'all'
30
30
  Requires-Dist: cloudpickle ~=3.0 ; extra == 'all'
31
31
  Requires-Dist: httpx[http2] ~=0.27 ; extra == 'all'
32
- Requires-Dist: jinja2 ~=3.1 ; extra == 'all'
33
32
  Requires-Dist: wrapt ~=1.14 ; extra == 'all'
34
33
  Requires-Dist: cryptography ~=43.0 ; extra == 'all'
35
34
  Requires-Dist: sqlalchemy[asyncio] ~=2.0 ; extra == 'all'
@@ -43,15 +42,15 @@ Requires-Dist: python-snappy ~=0.7 ; (python_version < "3.13") and extra == 'all
43
42
  Requires-Dist: asyncpg ~=0.29 ; (python_version < "3.13") and extra == 'all'
44
43
  Requires-Dist: sqlean.py ~=3.45 ; (python_version < "3.13") and extra == 'all'
45
44
  Provides-Extra: async
46
- Requires-Dist: anyio ~=4.4 ; extra == 'async'
45
+ Requires-Dist: anyio ~=4.5 ; extra == 'async'
47
46
  Requires-Dist: sniffio ~=1.3 ; extra == 'async'
48
47
  Requires-Dist: greenlet ~=3.1 ; extra == 'async'
49
48
  Requires-Dist: trio ~=0.26 ; extra == 'async'
50
49
  Requires-Dist: trio-asyncio ~=0.15 ; extra == 'async'
51
- Provides-Extra: compression
52
- Requires-Dist: lz4 ~=4.0 ; extra == 'compression'
53
- Requires-Dist: zstd ~=1.5 ; extra == 'compression'
54
- Requires-Dist: python-snappy ~=0.7 ; (python_version < "3.13") and extra == 'compression'
50
+ Provides-Extra: compress
51
+ Requires-Dist: lz4 ~=4.0 ; extra == 'compress'
52
+ Requires-Dist: zstd ~=1.5 ; extra == 'compress'
53
+ Requires-Dist: python-snappy ~=0.7 ; (python_version < "3.13") and extra == 'compress'
55
54
  Provides-Extra: diag
56
55
  Requires-Dist: asttokens ~=2.4 ; extra == 'diag'
57
56
  Requires-Dist: executing ~=2.1 ; extra == 'diag'
@@ -65,20 +64,19 @@ Requires-Dist: cloudpickle ~=3.0 ; extra == 'formats'
65
64
  Provides-Extra: http
66
65
  Requires-Dist: httpx[http2] ~=0.27 ; extra == 'http'
67
66
  Provides-Extra: misc
68
- Requires-Dist: jinja2 ~=3.1 ; extra == 'misc'
69
67
  Requires-Dist: wrapt ~=1.14 ; extra == 'misc'
70
68
  Provides-Extra: secrets
71
69
  Requires-Dist: cryptography ~=43.0 ; extra == 'secrets'
72
- Provides-Extra: sql
73
- Requires-Dist: sqlalchemy[asyncio] ~=2.0 ; extra == 'sql'
74
- Requires-Dist: pg8000 ~=1.31 ; extra == 'sql'
75
- Requires-Dist: pymysql ~=1.1 ; extra == 'sql'
76
- Requires-Dist: aiomysql ~=0.2 ; extra == 'sql'
77
- Requires-Dist: aiosqlite ~=0.20 ; extra == 'sql'
78
- Requires-Dist: asyncpg ~=0.29 ; (python_version < "3.13") and extra == 'sql'
79
- Provides-Extra: sqlx
80
- Requires-Dist: duckdb ~=1.1 ; extra == 'sqlx'
81
- Requires-Dist: sqlean.py ~=3.45 ; (python_version < "3.13") and extra == 'sqlx'
70
+ Provides-Extra: sqlalchemy
71
+ Requires-Dist: sqlalchemy[asyncio] ~=2.0 ; extra == 'sqlalchemy'
72
+ Provides-Extra: sqlalchemy-drivers
73
+ Requires-Dist: pg8000 ~=1.31 ; extra == 'sqlalchemy-drivers'
74
+ Requires-Dist: pymysql ~=1.1 ; extra == 'sqlalchemy-drivers'
75
+ Requires-Dist: aiomysql ~=0.2 ; extra == 'sqlalchemy-drivers'
76
+ Requires-Dist: aiosqlite ~=0.20 ; extra == 'sqlalchemy-drivers'
77
+ Requires-Dist: duckdb ~=1.1 ; extra == 'sqlalchemy-drivers'
78
+ Requires-Dist: asyncpg ~=0.29 ; (python_version < "3.13") and extra == 'sqlalchemy-drivers'
79
+ Requires-Dist: sqlean.py ~=3.45 ; (python_version < "3.13") and extra == 'sqlalchemy-drivers'
82
80
  Provides-Extra: testing
83
81
  Requires-Dist: pytest ~=8.0 ; extra == 'testing'
84
82
 
@@ -1,5 +1,5 @@
1
1
  omlish/.manifests.json,sha256=N1F-Xz3GaBn2H1p7uKzhkhKCQV8QVR0t76XD6wmFtXA,3
2
- omlish/__about__.py,sha256=SF90VIrjkctgajp8SFdNIxh69XQtRt20Y0ZhGvmT-3Q,2721
2
+ omlish/__about__.py,sha256=fDFLSSMSxswk3iOzGDNumjsP4JcRrkaXRbp8w77f4ok,2709
3
3
  omlish/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
4
  omlish/argparse.py,sha256=QRQmX9G0-L_nATkFtGHvpd4qrpYzKATdjuFLbBqzJPM,6224
5
5
  omlish/c3.py,sha256=W5EwYx9Por3rWYLkKUitJ6OoRMLLgVTfLTyroOz41Y0,8047
@@ -10,15 +10,14 @@ omlish/defs.py,sha256=T3bq_7h_tO3nDB5RAFBn7DkdeQgqheXzkFColbOHZko,4890
10
10
  omlish/docker.py,sha256=wipM7Xsx7rUv7-PoBTTT2v0uk3JVan0USljgm2QesXg,6227
11
11
  omlish/dynamic.py,sha256=35C_cCX_Vq2HrHzGk5T-zbrMvmUdiIiwDzDNixczoDo,6541
12
12
  omlish/fnpairs.py,sha256=hVuLqQFdRNNze3FYH2cAQO3GC7nK5yQP_GWPUSbL7nE,10601
13
+ omlish/fnpipes.py,sha256=AJkgz9nvRRm7oqw7ZgYyz21klu276LWi54oYCLg-vOg,2196
13
14
  omlish/genmachine.py,sha256=LCMiqvK32dAWtrlB6lKw9tXdQFiXC8rRdk4TMQYIroU,1603
14
15
  omlish/iterators.py,sha256=GGLC7RIT86uXMjhIIIqnff_Iu5SI_b9rXYywYGFyzmo,7292
15
16
  omlish/libc.py,sha256=u0481imCiTFqP_e-v9g0pD-0WD249j5vYzhtn-fnNkY,15308
16
17
  omlish/matchfns.py,sha256=ygqbqthRxgF9I1PJaw9Xl7FoZnAVMmnKBrYgimKQ0ag,6152
17
- omlish/math.py,sha256=AVqp5Y8yxKA-wO0BgrzaxA0Ga3PZiCXnYcwivMneC-0,3804
18
18
  omlish/multiprocessing.py,sha256=QZT4C7I-uThCAjaEY3xgUYb-5GagUlnE4etN01LDyU4,5186
19
- omlish/os.py,sha256=cz4nL2ujaxH_-XRq3JUD8af8mSe1JXGPIoXP9XAEd0M,2607
19
+ omlish/os.py,sha256=vO1sZCzAhVxo46tDFLrD52q2KuMFWQwu5MPJgSsnliI,3107
20
20
  omlish/runmodule.py,sha256=PWvuAaJ9wQQn6bx9ftEL3_d04DyotNn8dR_twm2pgw0,700
21
- omlish/stats.py,sha256=vJOJgYIW6DGDEgNm5AGWIp08GiLk61Cjld71fnC29fY,9998
22
21
  omlish/sync.py,sha256=AqwIfIuCMVHLwlJUa7dmaSjfA4sM5AYPCD5-nsz3XVQ,1516
23
22
  omlish/term.py,sha256=NEmxqAhicyInGtmFamZAizI2xdu819MzFYPEp0Fx97M,6111
24
23
  omlish/asyncs/__init__.py,sha256=uUz9ziKh4_QrgmdhKFMgq6j7mFbiZd3LiogguDCQsGI,587
@@ -50,7 +49,7 @@ omlish/collections/ordered.py,sha256=RzEC3fHvrDeJQSWThVDNYQKke263Vje1II5YwtDwT1Q
50
49
  omlish/collections/persistent.py,sha256=KG471s0bhhReQrjlmX0xaN9HeAIcrtT264ddZCxsExo,875
51
50
  omlish/collections/skiplist.py,sha256=xjuKZtSScp1VnOi9lpf7I090vGp1DnjA5ELjFhMeGps,5987
52
51
  omlish/collections/sorted.py,sha256=E5ZOdNn7Jju1EcQ7CX2Ltk9StIXsBOzqvh7EsT3ZA2U,3354
53
- omlish/collections/treap.py,sha256=wq9L5hvxq4QgPvIpHmueZMF8t7UrvX5vmlNN4BOqY4g,7720
52
+ omlish/collections/treap.py,sha256=A09ZPacGyJlyRB-Wi4TNj3tE0w-RpFNliPgpDaa6Vwg,7719
54
53
  omlish/collections/treapmap.py,sha256=TxOM-ZRF5PK2xe5wRIhESNt7DGh9b_MeZfE7HLkCOs4,5804
55
54
  omlish/collections/unmodifiable.py,sha256=QmUEi9IBXqiM_KGgH2rqg15VmkHJo1MZ6kwq2twEMho,4750
56
55
  omlish/collections/utils.py,sha256=9o9STwzAn5YjZRZ9ns1kuo7NgLXLaoVPFu6AJd-3JT8,4336
@@ -75,7 +74,7 @@ omlish/dataclasses/impl/as_.py,sha256=CD-t7hkC1EP2F_jvZKIA_cVoDuwZ-Ln_xC4fJumPYX
75
74
  omlish/dataclasses/impl/copy.py,sha256=Tn8_n6Vohs-w4otbGdubBEvhd3TsSTaM3EfNGdS2LYo,591
76
75
  omlish/dataclasses/impl/descriptors.py,sha256=rEYE1Len99agTQCC25hSPMnM19BgPr0ZChABGi58Fdk,2476
77
76
  omlish/dataclasses/impl/exceptions.py,sha256=DeiM6rcjgncudn-XVuph9TDbVDEwBtyYb1bcbO3FFcA,193
78
- omlish/dataclasses/impl/fields.py,sha256=yh2mwXVZW-eOhPesY-BG9sVMWSdn0VqzXNHkbs4Jmok,5987
77
+ omlish/dataclasses/impl/fields.py,sha256=DrFPLlPeJ4dCbbRsuwfx-y47Fx3iSllJP0YM5eq6nIE,6040
79
78
  omlish/dataclasses/impl/frozen.py,sha256=x87DSM8FIMZ3c_BIUE8NooCkExFjPsabeqIueEP5qKs,2988
80
79
  omlish/dataclasses/impl/hashing.py,sha256=FKnHuXCg9ylrzK2TLGqO5yfRN4HX3F415CSLlVYXtYE,3190
81
80
  omlish/dataclasses/impl/init.py,sha256=IgxO9nwHaHF8jGrUAk-Y5xke9uV2OwzfEe-88McE1Wg,6161
@@ -103,7 +102,7 @@ omlish/diag/threads.py,sha256=1-x02VCDZ407gfbtXm1pWK-ubqhqfePm9PMqkHCVoqk,3642
103
102
  omlish/diag/replserver/__init__.py,sha256=uLo6V2aQ29v9z3IMELlPDSlG3_2iOT4-_X8VniF-EgE,235
104
103
  omlish/diag/replserver/__main__.py,sha256=LmU41lQ58bm1h4Mx7S8zhE_uEBSC6kPcp9mn5JRpulA,32
105
104
  omlish/diag/replserver/console.py,sha256=XzBDVhYlr8FY6ym4OwoaIHuFOHnGK3dTYlMDIOMUUlA,7410
106
- omlish/diag/replserver/server.py,sha256=To2rLS-FHc0Ny8iFJaeEsU8ZZdkcWpk9bi1FYS7YNPA,5348
105
+ omlish/diag/replserver/server.py,sha256=5pRjBn-Vz8gtu45756ycdbJe58C_xrB9rElPytr6h5g,5345
107
106
  omlish/dispatch/__init__.py,sha256=GsiGJ91NKiQptSROtnCSkrZExBkvfDwYvdoTu5dBqF0,117
108
107
  omlish/dispatch/_dispatch2.py,sha256=v3tCNyxGpOwY8qTwdp54TlM8mG6OVwtQoUZfYJ_griU,1756
109
108
  omlish/dispatch/_dispatch3.py,sha256=Vnu5DfoPWFJLodudBqoZBXGTi2wYk-Az56MXJgdQvwc,2608
@@ -132,7 +131,7 @@ omlish/http/cookies.py,sha256=uuOYlHR6e2SC3GM41V0aozK10nef9tYg83Scqpn5-HM,6351
132
131
  omlish/http/dates.py,sha256=Otgp8wRxPgNGyzx8LFowu1vC4EKJYARCiAwLFncpfHM,2875
133
132
  omlish/http/encodings.py,sha256=w2WoKajpaZnQH8j-IBvk5ZFL2O2pAU_iBvZnkocaTlw,164
134
133
  omlish/http/json.py,sha256=9XwAsl4966Mxrv-1ytyCqhcE6lbBJw-0_tFZzGszgHE,7440
135
- omlish/http/sessions.py,sha256=gj_FgDoETAnLh_pISlwrqS78LFc1c3RNAKHSLYBEr5s,4793
134
+ omlish/http/sessions.py,sha256=VZ_WS5uiQG5y7i3u8oKuQMqf8dPKUOjFm_qk_0OvI8c,4793
136
135
  omlish/http/wsgi.py,sha256=czZsVUX-l2YTlMrUjKN49wRoP4rVpS0qpeBn4O5BoMY,948
137
136
  omlish/inject/__init__.py,sha256=JQ7x8l9MjU-kJ5ap7cPVq7SY7zbbCIrjyJAF0UeE5-s,1886
138
137
  omlish/inject/binder.py,sha256=H8AQ4ecmBOtDL8fMgrU1yUJl1gBADLNcdysRbvO8Wso,4167
@@ -164,27 +163,27 @@ omlish/inject/impl/privates.py,sha256=alpCYyk5VJ9lJknbRH2nLVNFYVvFhkj-VC1Vco3zCF
164
163
  omlish/inject/impl/providers.py,sha256=QnwhsujJFIHC0JTgd2Wlo1kP53i3CWTrj1nKU2DNxwg,2375
165
164
  omlish/inject/impl/proxy.py,sha256=1ko0VaKqzu9UG8bIldp9xtUrAVUOFTKWKTjOCqIGr4s,1636
166
165
  omlish/inject/impl/scopes.py,sha256=ASfULXgP_ETlsAqFJfrZmyEaZt64Zr8tNn5ScA-EoXk,5900
167
- omlish/lang/__init__.py,sha256=WF4vYG4awiOAXezL4gwCjzYu4JpzqU57U-w3c6rzoLw,3500
166
+ omlish/lang/__init__.py,sha256=0OCNjiSSyFL3RSNtakj0ILhC1K2P2WJkDTAgkC7xMjA,3601
168
167
  omlish/lang/cached.py,sha256=LwsgWQjQ5op618rBvI8vbASOEGWDTt_SKq6Tc1vlgZM,7680
169
168
  omlish/lang/clsdct.py,sha256=AjtIWLlx2E6D5rC97zQ3Lwq2SOMkbg08pdO_AxpzEHI,1744
170
169
  omlish/lang/cmp.py,sha256=5vbzWWbqdzDmNKAGL19z6ZfUKe5Ci49e-Oegf9f4BsE,1346
171
- omlish/lang/contextmanagers.py,sha256=rzMSwJU7ObFXl46r6pGDbD45Zi_qZ9NHxDPnLNuux9o,9732
170
+ omlish/lang/contextmanagers.py,sha256=NEwaTLQMfhKawD5x_0HgI2RpeLXbMa5r9NqWqfDnUXI,10408
172
171
  omlish/lang/datetimes.py,sha256=ehI_DhQRM-bDxAavnp470XcekbbXc4Gdw9y1KpHDJT0,223
173
172
  omlish/lang/descriptors.py,sha256=OLM1qi14kY7PLGIJnvkd6CBEOzHgD9q8Cs2cB6Kzflk,6602
174
173
  omlish/lang/exceptions.py,sha256=qJBo3NU1mOWWm-NhQUHCY5feYXR3arZVyEHinLsmRH4,47
175
- omlish/lang/functions.py,sha256=yJxWwqlXEAT2gied4uTwiz5x1qXeuVubOSXyn9zy5aI,3624
174
+ omlish/lang/functions.py,sha256=kkPfcdocg-OmyN7skIqrFxNvqAv89Zc_kXKYAN8vw8g,3895
176
175
  omlish/lang/imports.py,sha256=04ugFC8NI5sbL7NH4V0r0q_nFsP_AMkHLz697CVkMtQ,6274
177
176
  omlish/lang/iterables.py,sha256=_q6rHbdFfW3VBqez0IV3rUABoNxsA_oBv_sykm5zsbQ,2243
178
177
  omlish/lang/maybes.py,sha256=NYHZDjqDtwPMheDrj2VtUVujxRPf8Qpgk4ZlZCTvBZc,3492
179
178
  omlish/lang/objects.py,sha256=1dY8dX5voIZf5FBYUiN0BRsWg2JCdsgRbDl9fLG7OtY,4310
180
179
  omlish/lang/resolving.py,sha256=OuN2mDTPNyBUbcrswtvFKtj4xgH4H4WglgqSKv3MTy0,1606
181
- omlish/lang/resources.py,sha256=BD3EaLvTUPpUHfccfiSnnjuvlRhFwv_bcVOzwPPh1rw,2134
182
- omlish/lang/strings.py,sha256=ykeoou4JK7CEZXzrUJfqVOalEDvE--j0uhHt_SrsrUs,2834
180
+ omlish/lang/resources.py,sha256=-NmVTrSMKFZ6smVfOMz46ekZYVGgYh8cPooxQlFpG6s,2135
181
+ omlish/lang/strings.py,sha256=LqxR49cF5owHKpbUX8nUIBPsZ-4w7xqHPhlB-HIWqUg,3628
183
182
  omlish/lang/sys.py,sha256=UoZz_PJYVKLQAKqYxxn-LHz1okK_38I__maZgnXMcxU,406
184
183
  omlish/lang/timeouts.py,sha256=vECdWYhc_IZgcal1Ng1Y42wf2FV3KAx-i8As-MgGHIQ,1186
185
184
  omlish/lang/typing.py,sha256=lJ2NGe4Pmb61I0Tx4A_rOqXNFTws1XHOzafg2knRUio,4155
186
185
  omlish/lang/classes/__init__.py,sha256=h9QXrvAKD17_pIog0uF-7BCqZbSpJZYxL7kzVzvljp0,583
187
- omlish/lang/classes/abstract.py,sha256=goIV14oY24EOs88eVe6E6NyrSPOOLMOcWTXTMuYKiqc,2304
186
+ omlish/lang/classes/abstract.py,sha256=IRnjuLLNwpxvEJsp8fwoQdCIpw0MDAd0TiQfoDMgsn4,2306
188
187
  omlish/lang/classes/restrict.py,sha256=pSK7ZT_kpwqS6lWRrxwuEe-tt07F0-uZVazgGh-HDco,3921
189
188
  omlish/lang/classes/simple.py,sha256=JkWYrRWnSKil6kVMgXgRMJeCxkFHXQIKIzYtG1jK2Pk,3067
190
189
  omlish/lang/classes/virtual.py,sha256=W-QJuKsDehOcrydwg6eMN0bFPTYbk3Tz84TSH3blb44,3367
@@ -201,11 +200,11 @@ omlish/lite/cached.py,sha256=dUm647FbIsoxWT23XUFM51F7i-C2Buxr5b5zzgbCtQI,546
201
200
  omlish/lite/check.py,sha256=DYxkYkxpnQpjGpDwW_8M8YBXbswvnBUCr0UBPU7aNKo,642
202
201
  omlish/lite/contextmanagers.py,sha256=HnQJiyrOmSvTL22XRJrFl5CLpCyHD9fsntEUAr9G-60,427
203
202
  omlish/lite/json.py,sha256=7-02Ny4fq-6YAu5ynvqoijhuYXWpLmfCI19GUeZnb1c,740
204
- omlish/lite/logs.py,sha256=PeJZUJWd1K-UFErVs0wtD0zRMFW5-olUNFVVZAj_ScY,5549
203
+ omlish/lite/logs.py,sha256=vkFkSX0Izb2P-NNMqqNLSec0BzeLOtHoQWgdXwQuDPU,6007
205
204
  omlish/lite/marshal.py,sha256=u6jYUN_AndvI6__HJBvSw5ElHWC0CfHqgiDS28Vpqjg,8593
206
205
  omlish/lite/reflect.py,sha256=9QYJwdINraq1JNMEgvoqeSlVvRRgOXpxAkpgX8EgRXc,1307
207
206
  omlish/lite/runtime.py,sha256=VUhmNQvwf8QzkWSKj4Q0ReieJA_PzHaJNRBivfTseow,452
208
- omlish/lite/secrets.py,sha256=KZvGG7bFrjzIeLwohxsJ0Ctzpi42C-3A1PEMCIszJJs,521
207
+ omlish/lite/secrets.py,sha256=3Mz3V2jf__XU9qNHcH56sBSw95L3U2UPL24bjvobG0c,816
209
208
  omlish/lite/strings.py,sha256=9dO_A6EkhcTZ2xmOUGSOMT-mx9BnoOzYu1-ocSrDJaA,670
210
209
  omlish/lite/subprocesses.py,sha256=KuGV3ImehMjCUK0JoV3pUtG_7o5wei1lRDn9HxzByAg,3063
211
210
  omlish/logs/__init__.py,sha256=FbOyAW-lGH8gyBlSVArwljdYAU6RnwZLI5LwAfuNnrk,438
@@ -230,11 +229,11 @@ omlish/marshal/helpers.py,sha256=YA0pNo-Fkc-_qKeoRNXUpP36js8oelU7uENkvoGD4hY,120
230
229
  omlish/marshal/iterables.py,sha256=6I_ZdJemLSQtJ4J5NrB9wi-eyxiJZS61HzHXp1yeiX8,2592
231
230
  omlish/marshal/mappings.py,sha256=zhLtyot7tzQtBNj7C4RBxjMELxA5r2q2Mth8Br7xkFs,2803
232
231
  omlish/marshal/maybes.py,sha256=tKkVsJATERgbVcEfBnsHBK_2_LCQIVyBzca-cA-9KH0,2112
233
- omlish/marshal/naming.py,sha256=UCviMAXTTUpW1lyAGymybGP2rFUAW44P1X0zrIVbvi4,464
232
+ omlish/marshal/naming.py,sha256=lIklR_Od4x1ghltAgOzqcKhHs-leeSv2YmFhCHO7GIs,613
234
233
  omlish/marshal/numbers.py,sha256=oY_yMNJEnJhjfLh89gpPXvKqeUyhQcaTcQB6ecyHiG8,1704
235
234
  omlish/marshal/objects.py,sha256=R-NPCT1-UZhONTnrsrAvZvAtM2qyQsKZ8CPLfqkSg5g,4494
236
235
  omlish/marshal/optionals.py,sha256=r0XB5rqfasvgZJNrKYd6Unq2U4nHt3JURi26j0dYHlw,1499
237
- omlish/marshal/polymorphism.py,sha256=gyvNYUAkmQVhWrcXBLzXINxqx6RHyulf9n16Iv38PFI,5597
236
+ omlish/marshal/polymorphism.py,sha256=doA8aLUhna6aco5b2Ok3jsem1V4NsF3rM5RTfJt0a7U,5708
238
237
  omlish/marshal/primitives.py,sha256=wcvcs5GH_TWVmzAszh3dvyKibJgBxnXke-AlAXiwrrI,1107
239
238
  omlish/marshal/registries.py,sha256=GI2KogcxawMkk02Ky7-TsnijChoe1I7YTOPIbUNwSAI,1665
240
239
  omlish/marshal/standard.py,sha256=uQZIGiCwihmhB1tmhpKnZWZly0DDkdGjCnN0d41WHho,2985
@@ -242,6 +241,10 @@ omlish/marshal/unions.py,sha256=m9uVp2HrkZKY9lDyGoWQGXFgan8mRuBaKimtWNksl64,2635
242
241
  omlish/marshal/utils.py,sha256=puKJpwPpuDlMOIrKMcLTRLJyMiL6n_Xs-p59AuDEymA,543
243
242
  omlish/marshal/uuids.py,sha256=H4B7UX_EPNmP2tC8bubcKrPLTS4aQu98huvbXQ3Zv2g,910
244
243
  omlish/marshal/values.py,sha256=ssHiWdg_L6M17kAn8GiGdPW7UeQOm3RDikWkvwblf5I,263
244
+ omlish/math/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
245
+ omlish/math/bits.py,sha256=yip1l8agOYzT7bFyMGc0RR3XlnGCfHMpjw_SECLLh1I,3477
246
+ omlish/math/floats.py,sha256=UimhOT7KRl8LXTzOI5cQWoX_9h6WNWe_3vcOuO7-h_8,327
247
+ omlish/math/stats.py,sha256=MegzKVsmv2kra4jDWLOUgV0X7Ee2Tbl5u6ql1v4-dEY,10053
245
248
  omlish/reflect/__init__.py,sha256=iWDCNJNP4afPcv-MxZRJSIRQ4NRw6XYPyRHhBXb5YIA,667
246
249
  omlish/reflect/isinstance.py,sha256=x5T9S2634leinBT4hl3CZZkRttvdvvlxChkC_x9Qu2s,1176
247
250
  omlish/reflect/ops.py,sha256=RJ6jzrM4ieFsXzWyNXWV43O_WgzEaUvlHSc5N2ezW2A,2044
@@ -254,7 +257,7 @@ omlish/secrets/openssl.py,sha256=wxA_wIlxtuOUy71ABxAJgavh-UI_taOfm-A0dVlmSwM,621
254
257
  omlish/secrets/passwords.py,sha256=3r-vEK6Gp6aq4L5Csnd06QnrjO9xfzHJP-g_7I9W_ao,4101
255
258
  omlish/secrets/secrets.py,sha256=ClD7t_mkmWkseVk4ahLzYLuLXeTxiwwPiidYm42vLh4,6871
256
259
  omlish/secrets/subprocesses.py,sha256=EcnKlHHtnUMHGrBWXDfu8tv28wlgZx4P4GOiuPW9Vo8,1105
257
- omlish/specs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
260
+ omlish/specs/__init__.py,sha256=_CSPXx25uGhXkmqLs9CSdcWAkZaQnc3cJk3lb2dadgE,88
258
261
  omlish/specs/jsonschema/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
259
262
  omlish/specs/jsonschema/types.py,sha256=qoxExgKfrI-UZXdk3qcVZIEyp1WckFbb85_eGInEoAY,467
260
263
  omlish/specs/jsonschema/keywords/__init__.py,sha256=Zt2g1BXd654uU2AQ5P7_-x2Wrtf6cNbP9mxI1wGN4wo,596
@@ -277,15 +280,16 @@ omlish/specs/jsonschema/schemas/draft202012/vocabularies/format.json,sha256=UOu_
277
280
  omlish/specs/jsonschema/schemas/draft202012/vocabularies/meta-data.json,sha256=j3bW4U9Bubku-TO3CM3FFEyLUmhlGtEZGEhfsXVPHHY,892
278
281
  omlish/specs/jsonschema/schemas/draft202012/vocabularies/unevaluated.json,sha256=Lb-8tzmUtnCwl2SSre4f_7RsIWgnhNL1pMpWH54tDLQ,506
279
282
  omlish/specs/jsonschema/schemas/draft202012/vocabularies/validation.json,sha256=cBCjHlQfMtK-ch4t40jfdcmzaHaj7TBId_wKvaHTelg,2834
280
- omlish/sql/__init__.py,sha256=QHKkiM0rvSDWKUYrvTSynOni5fB46QQ2gOw_TcMBQ2o,398
283
+ omlish/sql/__init__.py,sha256=TpZLsEJKJzvJ0eMzuV8hwOJJbkxBCV1RZPUMLAVB6io,173
281
284
  omlish/sql/_abc.py,sha256=HLhnnLZ7l0r_N99I-RCqJe6VHth-9iluU7cR-7-5jfs,1519
282
- omlish/sql/asyncs.py,sha256=Wye3dwh7oZEGYz2Y4DZQSHtW4xjI2AH5qjW-BSS2IfU,3688
283
285
  omlish/sql/dbs.py,sha256=lpdFmm2vTwLoBiVYGj9yPsVcTEYYNCxlYZZpjfChzkY,1870
284
- omlish/sql/duckdb.py,sha256=Z3wiZEn_21Lu1ElFRX0ATzoBMCw0KJxINjTRuTexYGM,3748
285
- omlish/sql/exprs.py,sha256=gO4Fj4xEY-PuDgV-N8hBMy55glZz7O-4H7v1LWabfZY,323
286
286
  omlish/sql/qualifiedname.py,sha256=rlW3gVmyucJbqwcxj_7BfK4X2HoXrMroZT2H45zPgJQ,2264
287
- omlish/sql/secrets.py,sha256=mDUunIACxHBsPD_ONbHQJVndeMMzJR4vMC2WWX7tGfY,177
288
- omlish/sql/sqlean.py,sha256=RbkuOuFIfM4fowwKk8-sQ6Dxk-tTUwxS94nY5Kxt52s,403
287
+ omlish/sql/alchemy/__init__.py,sha256=1ruDMiviH5fjevn2xVki-QspcE9O3VPy4hxOqpHjI2s,224
288
+ omlish/sql/alchemy/asyncs.py,sha256=C1bIzz9m2Qbgl4qYGQt_FRQg4BKRcxUqMsVg9RtnTPg,3689
289
+ omlish/sql/alchemy/duckdb.py,sha256=kr7pIhiBLNAuZrcigHDtFg9zHkVcrRW3LfryO9VJ4mk,3749
290
+ omlish/sql/alchemy/exprs.py,sha256=gO4Fj4xEY-PuDgV-N8hBMy55glZz7O-4H7v1LWabfZY,323
291
+ omlish/sql/alchemy/secrets.py,sha256=EMfy4EfTbEvrlv_41oOhn8qsoF-eTkY7HciPenIE6rI,178
292
+ omlish/sql/alchemy/sqlean.py,sha256=RbkuOuFIfM4fowwKk8-sQ6Dxk-tTUwxS94nY5Kxt52s,403
289
293
  omlish/testing/__init__.py,sha256=kfiF10ykrjWXniedIl3g8j3pNAFyuSbp1D3ZXug3-Eo,168
290
294
  omlish/testing/testing.py,sha256=pJUbZ0ymdrQoNG9r9UlGXypeU1x9ntEp9xcYBnyOHUs,3088
291
295
  omlish/testing/pytest/__init__.py,sha256=b6ObMEHTZnvGEI_de6nN1x5FyitV6B2mNYkurA4Q7fo,336
@@ -295,7 +299,7 @@ omlish/testing/pytest/inject/__init__.py,sha256=pdRKv1HcDmJ_yArKJbYITPXXZthRSGgB
295
299
  omlish/testing/pytest/inject/harness.py,sha256=sMKjP2EWHq-eeTB1YVXcANli2Czxt56_9ERg4HtkVPg,5810
296
300
  omlish/testing/pytest/plugins/__init__.py,sha256=ys1zXrYrNm7Uo6YOIVJ6Bd3dQo6kv387k7MbTYlqZSI,467
297
301
  omlish/testing/pytest/plugins/_registry.py,sha256=IK04KlBgiOJxKAyCCgjpX2R-9tE-btalYJkgjLc8Te8,77
298
- omlish/testing/pytest/plugins/asyncs.py,sha256=1eiKJMzSxhMMGHXbYyCTDElTyRrA31sK5Q80JR9YlBE,5054
302
+ omlish/testing/pytest/plugins/asyncs.py,sha256=SV6oKCy50CGkzLGYX-CT4MfWNqsrH8ONEbIWC3tFcHA,5324
299
303
  omlish/testing/pytest/plugins/depskip.py,sha256=xithY-OMtjwhv8mcRNkv-WI_PSQtHldQ8H1s60MIXkk,2673
300
304
  omlish/testing/pytest/plugins/logging.py,sha256=1zs6Xe54wiaSjabCviaFXwKkoN97CKm3mA5mEoUeJGs,380
301
305
  omlish/testing/pytest/plugins/managermarks.py,sha256=pDEcCNdDAcTS4jjZHSnAfmzqMJDBcJcSsM3QNhbJ6Gs,1485
@@ -306,13 +310,13 @@ omlish/testing/pytest/plugins/spacing.py,sha256=JQQhi9q3c523Ro1a_K_9RGAb7HotiO74
306
310
  omlish/testing/pytest/plugins/switches.py,sha256=9FtN5qtPBoS-teEp54OHPF6jlZJakRJdq4pnLJpPj_A,3001
307
311
  omlish/testing/pytest/plugins/utils.py,sha256=L5C622UXcA_AUKDcvyh5IMiRfqSGGz0McdhwZWvfMlU,261
308
312
  omlish/text/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
309
- omlish/text/asdl.py,sha256=9Zbd8az7jum1EqRYuNaKyRFG58WA56G4nLHWc_NBN8g,16856
313
+ omlish/text/asdl.py,sha256=3v5UocAfxan_d9drkGNdH3AMfx_FFBpQu3ULGL4M6VM,16865
310
314
  omlish/text/delimit.py,sha256=ubPXcXQmtbOVrUsNh5gH1mDq5H-n1y2R4cPL5_DQf68,4928
311
315
  omlish/text/glyphsplit.py,sha256=Ug-dPRO7x-OrNNr8g1y6DotSZ2KH0S-VcOmUobwa4B0,3296
312
316
  omlish/text/indent.py,sha256=6Jj6TFY9unaPa4xPzrnZemJ-fHsV53IamP93XGjSUHs,1274
313
- omlish/text/parts.py,sha256=KGgo0wHOIMVMZtDso-rhSWKAcAkYAH2IGpg9tULabu8,6505
314
- omlish-0.0.0.dev28.dist-info/LICENSE,sha256=B_hVtavaA8zCYDW99DYdcpDLKz1n3BBRjZrcbv8uG8c,1451
315
- omlish-0.0.0.dev28.dist-info/METADATA,sha256=kz-tHFHaXXkqK4NutvYQ6Uvxag9ogDnJFyUX0DgBrFo,3666
316
- omlish-0.0.0.dev28.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
317
- omlish-0.0.0.dev28.dist-info/top_level.txt,sha256=pePsKdLu7DvtUiecdYXJ78iO80uDNmBlqe-8hOzOmfs,7
318
- omlish-0.0.0.dev28.dist-info/RECORD,,
317
+ omlish/text/parts.py,sha256=7vPF1aTZdvLVYJ4EwBZVzRSy8XB3YqPd7JwEnNGGAOo,6495
318
+ omlish-0.0.0.dev30.dist-info/LICENSE,sha256=B_hVtavaA8zCYDW99DYdcpDLKz1n3BBRjZrcbv8uG8c,1451
319
+ omlish-0.0.0.dev30.dist-info/METADATA,sha256=IwpExBB3pJdmS4yOOGHNJjwusV5Xj5KOyW5aY9cHxV8,3694
320
+ omlish-0.0.0.dev30.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
321
+ omlish-0.0.0.dev30.dist-info/top_level.txt,sha256=pePsKdLu7DvtUiecdYXJ78iO80uDNmBlqe-8hOzOmfs,7
322
+ omlish-0.0.0.dev30.dist-info/RECORD,,
File without changes
File without changes