omlish 0.0.0.dev29__py3-none-any.whl → 0.0.0.dev31__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 +6 -6
- omlish/asyncs/anyio.py +1 -1
- omlish/asyncs/bridge.py +17 -9
- omlish/asyncs/trio.py +1 -1
- omlish/bootstrap/main.py +5 -0
- omlish/concurrent/threadlets.py +2 -2
- omlish/diag/replserver/server.py +1 -1
- omlish/docker.py +9 -0
- omlish/fnpipes.py +82 -0
- omlish/http/sessions.py +2 -2
- omlish/lang/__init__.py +4 -0
- omlish/lang/classes/abstract.py +1 -1
- omlish/lang/contextmanagers.py +35 -0
- omlish/lang/resources.py +1 -0
- omlish/lang/strings.py +49 -1
- omlish/lite/logs.py +20 -5
- omlish/logs/noisy.py +1 -0
- omlish/marshal/naming.py +5 -0
- omlish/marshal/polymorphism.py +20 -10
- omlish/matchfns.py +2 -2
- omlish/os.py +17 -0
- omlish/specs/__init__.py +9 -0
- omlish/sql/__init__.py +0 -14
- omlish/sql/alchemy/__init__.py +13 -0
- omlish/sql/{asyncs.py → alchemy/asyncs.py} +1 -1
- omlish/sql/{duckdb.py → alchemy/duckdb.py} +1 -1
- omlish/sql/{secrets.py → alchemy/secrets.py} +1 -1
- omlish/testing/pytest/plugins/asyncs.py +5 -0
- omlish/testing/pytest/plugins/switches.py +29 -9
- {omlish-0.0.0.dev29.dist-info → omlish-0.0.0.dev31.dist-info}/METADATA +17 -17
- {omlish-0.0.0.dev29.dist-info → omlish-0.0.0.dev31.dist-info}/RECORD +36 -34
- /omlish/sql/{exprs.py → alchemy/exprs.py} +0 -0
- /omlish/sql/{sqlean.py → alchemy/sqlean.py} +0 -0
- {omlish-0.0.0.dev29.dist-info → omlish-0.0.0.dev31.dist-info}/LICENSE +0 -0
- {omlish-0.0.0.dev29.dist-info → omlish-0.0.0.dev31.dist-info}/WHEEL +0 -0
- {omlish-0.0.0.dev29.dist-info → omlish-0.0.0.dev31.dist-info}/top_level.txt +0 -0
omlish/__about__.py
CHANGED
@@ -1,5 +1,5 @@
|
|
1
|
-
__version__ = '0.0.0.
|
2
|
-
__revision__ = '
|
1
|
+
__version__ = '0.0.0.dev31'
|
2
|
+
__revision__ = 'bd655a8d18c1cc31ce2c9d79fedaec771c5e1593'
|
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.
|
33
|
+
'anyio ~= 4.6',
|
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
|
-
'
|
42
|
+
'compress': [
|
43
43
|
'lz4 ~= 4.0',
|
44
44
|
|
45
45
|
'python-snappy ~= 0.7; python_version < "3.13"',
|
@@ -77,11 +77,11 @@ class Project(ProjectBase):
|
|
77
77
|
'cryptography ~= 43.0',
|
78
78
|
],
|
79
79
|
|
80
|
-
'
|
80
|
+
'sqlalchemy': [
|
81
81
|
'sqlalchemy[asyncio] ~= 2.0',
|
82
82
|
],
|
83
83
|
|
84
|
-
'
|
84
|
+
'sqlalchemy-drivers': [
|
85
85
|
'pg8000 ~= 1.31',
|
86
86
|
# 'psycopg2 ~= 2.9',
|
87
87
|
# 'psycopg ~= 3.2',
|
omlish/asyncs/anyio.py
CHANGED
@@ -4,7 +4,7 @@ TODO:
|
|
4
4
|
- owned lock
|
5
5
|
- async once
|
6
6
|
|
7
|
-
|
7
|
+
See:
|
8
8
|
- https://github.com/davidbrochart/sqlite-anyio/blob/a3ba4c6ef0535b14a5a60071fcd6ed565a514963/sqlite_anyio/sqlite.py
|
9
9
|
- https://github.com/rafalkrupinski/ratelimit-anyio/blob/2910a8a3d6fa54ed17ee6ba457686c9f7a4c4beb/src/ratelimit_anyio/__init__.py
|
10
10
|
- https://github.com/nekitdev/async-extensions/tree/main/async_extensions
|
omlish/asyncs/bridge.py
CHANGED
@@ -12,8 +12,9 @@ TODO:
|
|
12
12
|
See:
|
13
13
|
- https://greenback.readthedocs.io/en/latest/
|
14
14
|
"""
|
15
|
+
import functools # noqa
|
15
16
|
import itertools
|
16
|
-
import sys
|
17
|
+
import sys # noqa
|
17
18
|
import types
|
18
19
|
import typing as ta
|
19
20
|
import weakref
|
@@ -90,7 +91,7 @@ class UnexpectedBridgeNestingError(Exception):
|
|
90
91
|
|
91
92
|
|
92
93
|
_DEBUG_PRINT: ta.Callable[..., None] | None = None
|
93
|
-
# _DEBUG_PRINT = print # noqa
|
94
|
+
# _DEBUG_PRINT = functools.partial(print, file=sys.stderr) # noqa
|
94
95
|
|
95
96
|
_TRACK_TRANSITION_OBJS = False
|
96
97
|
|
@@ -253,8 +254,8 @@ def s_to_a(fn, *, require_await=False):
|
|
253
254
|
switch_occurred = True
|
254
255
|
try:
|
255
256
|
value = yield result
|
256
|
-
except BaseException: # noqa
|
257
|
-
result = g.throw(
|
257
|
+
except BaseException as e: # noqa
|
258
|
+
result = g.throw(e)
|
258
259
|
else:
|
259
260
|
result = g.switch(value)
|
260
261
|
|
@@ -302,15 +303,22 @@ def a_to_s(fn):
|
|
302
303
|
|
303
304
|
cr = gate()
|
304
305
|
sv = None
|
306
|
+
he = False
|
305
307
|
try:
|
306
308
|
while True:
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
309
|
+
if not he:
|
310
|
+
try:
|
311
|
+
sv = cr.send(sv)
|
312
|
+
except StopIteration:
|
313
|
+
break
|
314
|
+
he = False
|
311
315
|
|
312
316
|
if ret is missing or cr.cr_await is not None or cr.cr_running:
|
313
|
-
|
317
|
+
try:
|
318
|
+
sv = s_to_a_await(sv) # type: ignore
|
319
|
+
except BaseException as e: # noqa
|
320
|
+
sv = cr.throw(e)
|
321
|
+
he = True
|
314
322
|
|
315
323
|
finally:
|
316
324
|
cr.close()
|
omlish/asyncs/trio.py
CHANGED
omlish/bootstrap/main.py
CHANGED
omlish/concurrent/threadlets.py
CHANGED
@@ -48,7 +48,7 @@ class Threadlet(abc.ABC):
|
|
48
48
|
raise NotImplementedError
|
49
49
|
|
50
50
|
@abc.abstractmethod
|
51
|
-
def throw(self, ex:
|
51
|
+
def throw(self, ex: BaseException) -> ta.Any:
|
52
52
|
raise NotImplementedError
|
53
53
|
|
54
54
|
|
@@ -84,7 +84,7 @@ class GreenletThreadlet(Threadlet):
|
|
84
84
|
def switch(self, *args: ta.Any, **kwargs: ta.Any) -> ta.Any:
|
85
85
|
return self.g.switch(*args, **kwargs)
|
86
86
|
|
87
|
-
def throw(self, ex:
|
87
|
+
def throw(self, ex: BaseException) -> ta.Any:
|
88
88
|
return self.g.throw(ex)
|
89
89
|
|
90
90
|
|
omlish/diag/replserver/server.py
CHANGED
@@ -9,7 +9,7 @@ TODO:
|
|
9
9
|
- optional ipython embed
|
10
10
|
- https://github.com/python/cpython/tree/56470004e58911b146c016fc9fec4461b8f69454/Lib/_pyrepl
|
11
11
|
|
12
|
-
|
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/docker.py
CHANGED
@@ -107,6 +107,15 @@ def cli_inspect(ids: list[str]) -> list[Inspect]:
|
|
107
107
|
return msh.unmarshal(json.loads(o.decode()), list[Inspect])
|
108
108
|
|
109
109
|
|
110
|
+
def has_cli() -> bool:
|
111
|
+
try:
|
112
|
+
proc = subprocess.run(['docker', '--version']) # noqa
|
113
|
+
except (FileNotFoundError, subprocess.CalledProcessError):
|
114
|
+
return False
|
115
|
+
else:
|
116
|
+
return not proc.returncode
|
117
|
+
|
118
|
+
|
110
119
|
##
|
111
120
|
|
112
121
|
|
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
|
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:
|
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,
|
@@ -188,8 +189,11 @@ from .strings import ( # noqa
|
|
188
189
|
is_ident_cont,
|
189
190
|
is_ident_start,
|
190
191
|
is_sunder,
|
192
|
+
prefix_delimited,
|
191
193
|
prefix_lines,
|
192
194
|
snake_case,
|
195
|
+
strip_prefix,
|
196
|
+
strip_suffix,
|
193
197
|
)
|
194
198
|
|
195
199
|
from .sys import ( # noqa
|
omlish/lang/classes/abstract.py
CHANGED
@@ -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
|
|
omlish/lang/contextmanagers.py
CHANGED
@@ -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/resources.py
CHANGED
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
|
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
|
-
|
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/logs/noisy.py
CHANGED
omlish/marshal/naming.py
CHANGED
omlish/marshal/polymorphism.py
CHANGED
@@ -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
|
-
|
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
|
|
omlish/matchfns.py
CHANGED
@@ -130,7 +130,7 @@ def multi(*children: MatchFn[P, T], strict: bool = False) -> MultiMatchFn: # Mu
|
|
130
130
|
##
|
131
131
|
|
132
132
|
|
133
|
-
class
|
133
|
+
class CachedMatchFn(MatchFn[P, T]):
|
134
134
|
@staticmethod
|
135
135
|
def _default_key(*args, **kwargs):
|
136
136
|
return (args, tuple(sorted(kwargs.items(), key=lambda t: t[0])))
|
@@ -187,7 +187,7 @@ class CachedMultiFn(MatchFn[P, T]):
|
|
187
187
|
return self.__class__(self._f.__get__(instance, owner), key=self._key) # noqa
|
188
188
|
|
189
189
|
|
190
|
-
cached =
|
190
|
+
cached = CachedMatchFn
|
191
191
|
|
192
192
|
|
193
193
|
##
|
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
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,
|
@@ -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
|
|
@@ -10,19 +10,24 @@ import pytest
|
|
10
10
|
|
11
11
|
from .... import check
|
12
12
|
from .... import collections as col
|
13
|
+
from .... import docker
|
14
|
+
from .... import lang
|
13
15
|
from ._registry import register
|
14
16
|
|
15
17
|
|
16
18
|
Configable = pytest.FixtureRequest | pytest.Config
|
17
19
|
|
18
20
|
|
19
|
-
SWITCHES = {
|
20
|
-
'docker':
|
21
|
+
SWITCHES: ta.Mapping[str, bool | ta.Callable[[], bool]] = {
|
22
|
+
'docker': docker.has_cli,
|
23
|
+
'docker-guest': docker.is_likely_in_docker,
|
21
24
|
'online': True,
|
22
25
|
'integration': True,
|
23
26
|
'slow': False,
|
24
27
|
}
|
25
28
|
|
29
|
+
SWITCH_ATTRS = {k.replace('-', '_'): k for k in SWITCHES}
|
30
|
+
|
26
31
|
|
27
32
|
SwitchState: ta.TypeAlias = bool | ta.Literal['only']
|
28
33
|
|
@@ -53,9 +58,9 @@ def skip_if_disabled(obj: Configable | None, name: str) -> None:
|
|
53
58
|
pytest.skip(f'{name} disabled')
|
54
59
|
|
55
60
|
|
56
|
-
def
|
61
|
+
def get_specified_switches(obj: Configable) -> ta.Mapping[str, SwitchState]:
|
57
62
|
ret: dict[str, SwitchState] = {}
|
58
|
-
for sw
|
63
|
+
for sw in SWITCHES:
|
59
64
|
sts = {
|
60
65
|
st
|
61
66
|
for st, pfx in SWITCH_STATE_OPT_PREFIXES.items()
|
@@ -65,8 +70,6 @@ def get_switches(obj: Configable) -> ta.Mapping[str, SwitchState]:
|
|
65
70
|
if len(sts) > 1:
|
66
71
|
raise Exception(f'Multiple switches specified for {sw}')
|
67
72
|
ret[sw] = check.single(sts)
|
68
|
-
else:
|
69
|
-
ret[sw] = d
|
70
73
|
return ret
|
71
74
|
|
72
75
|
|
@@ -74,8 +77,9 @@ def get_switches(obj: Configable) -> ta.Mapping[str, SwitchState]:
|
|
74
77
|
class SwitchesPlugin:
|
75
78
|
|
76
79
|
def pytest_configure(self, config):
|
77
|
-
for sw in
|
80
|
+
for sw in SWITCH_ATTRS:
|
78
81
|
config.addinivalue_line('markers', f'{sw}: mark test as {sw}')
|
82
|
+
config.addinivalue_line('markers', f'not_{sw}: mark test as not {sw}')
|
79
83
|
|
80
84
|
def pytest_addoption(self, parser):
|
81
85
|
for sw in SWITCHES:
|
@@ -83,13 +87,25 @@ class SwitchesPlugin:
|
|
83
87
|
parser.addoption(f'--{sw}', action='store_true', default=False, help=f'enables {sw} tests')
|
84
88
|
parser.addoption(f'--only-{sw}', action='store_true', default=False, help=f'enables only {sw} tests')
|
85
89
|
|
90
|
+
@lang.cached_function
|
91
|
+
def get_switches(self) -> ta.Mapping[str, SwitchState]:
|
92
|
+
return {
|
93
|
+
k: v() if callable(v) else v
|
94
|
+
for k, v in SWITCHES.items()
|
95
|
+
}
|
96
|
+
|
86
97
|
def pytest_collection_modifyitems(self, config, items):
|
87
|
-
sts =
|
98
|
+
sts = {
|
99
|
+
**self.get_switches(),
|
100
|
+
**get_specified_switches(config),
|
101
|
+
}
|
102
|
+
|
88
103
|
stx = col.multi_map(map(reversed, sts.items())) # type: ignore
|
89
104
|
ts, fs, onlys = (stx.get(k, ()) for k in (True, False, 'only'))
|
90
105
|
|
91
106
|
def process(item):
|
92
|
-
sws = {sw for sw in
|
107
|
+
sws = {sw for swa, sw in SWITCH_ATTRS.items() if swa in item.keywords}
|
108
|
+
nsws = {sw for swa, sw in SWITCH_ATTRS.items() if ('not_' + swa) in item.keywords}
|
93
109
|
|
94
110
|
if onlys:
|
95
111
|
if not any(sw in onlys for sw in sws):
|
@@ -101,5 +117,9 @@ class SwitchesPlugin:
|
|
101
117
|
if sw in fs:
|
102
118
|
item.add_marker(pytest.mark.skip(reason=f'skipping switches {sw}'))
|
103
119
|
|
120
|
+
for nsw in nsws:
|
121
|
+
if nsw in ts:
|
122
|
+
item.add_marker(pytest.mark.skip(reason=f'skipping switches {nsw}'))
|
123
|
+
|
104
124
|
for item in items:
|
105
125
|
process(item)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: omlish
|
3
|
-
Version: 0.0.0.
|
3
|
+
Version: 0.0.0.dev31
|
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.
|
16
|
+
Requires-Dist: anyio ~=4.6 ; 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'
|
@@ -42,15 +42,15 @@ Requires-Dist: python-snappy ~=0.7 ; (python_version < "3.13") and extra == 'all
|
|
42
42
|
Requires-Dist: asyncpg ~=0.29 ; (python_version < "3.13") and extra == 'all'
|
43
43
|
Requires-Dist: sqlean.py ~=3.45 ; (python_version < "3.13") and extra == 'all'
|
44
44
|
Provides-Extra: async
|
45
|
-
Requires-Dist: anyio ~=4.
|
45
|
+
Requires-Dist: anyio ~=4.6 ; extra == 'async'
|
46
46
|
Requires-Dist: sniffio ~=1.3 ; extra == 'async'
|
47
47
|
Requires-Dist: greenlet ~=3.1 ; extra == 'async'
|
48
48
|
Requires-Dist: trio ~=0.26 ; extra == 'async'
|
49
49
|
Requires-Dist: trio-asyncio ~=0.15 ; extra == 'async'
|
50
|
-
Provides-Extra:
|
51
|
-
Requires-Dist: lz4 ~=4.0 ; extra == '
|
52
|
-
Requires-Dist: zstd ~=1.5 ; extra == '
|
53
|
-
Requires-Dist: python-snappy ~=0.7 ; (python_version < "3.13") and extra == '
|
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'
|
54
54
|
Provides-Extra: diag
|
55
55
|
Requires-Dist: asttokens ~=2.4 ; extra == 'diag'
|
56
56
|
Requires-Dist: executing ~=2.1 ; extra == 'diag'
|
@@ -67,16 +67,16 @@ Provides-Extra: misc
|
|
67
67
|
Requires-Dist: wrapt ~=1.14 ; extra == 'misc'
|
68
68
|
Provides-Extra: secrets
|
69
69
|
Requires-Dist: cryptography ~=43.0 ; extra == 'secrets'
|
70
|
-
Provides-Extra:
|
71
|
-
Requires-Dist: sqlalchemy[asyncio] ~=2.0 ; extra == '
|
72
|
-
Provides-Extra:
|
73
|
-
Requires-Dist: pg8000 ~=1.31 ; extra == '
|
74
|
-
Requires-Dist: pymysql ~=1.1 ; extra == '
|
75
|
-
Requires-Dist: aiomysql ~=0.2 ; extra == '
|
76
|
-
Requires-Dist: aiosqlite ~=0.20 ; extra == '
|
77
|
-
Requires-Dist: duckdb ~=1.1 ; extra == '
|
78
|
-
Requires-Dist: asyncpg ~=0.29 ; (python_version < "3.13") and extra == '
|
79
|
-
Requires-Dist: sqlean.py ~=3.45 ; (python_version < "3.13") and extra == '
|
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'
|
80
80
|
Provides-Extra: testing
|
81
81
|
Requires-Dist: pytest ~=8.0 ; extra == 'testing'
|
82
82
|
|
@@ -1,5 +1,5 @@
|
|
1
1
|
omlish/.manifests.json,sha256=N1F-Xz3GaBn2H1p7uKzhkhKCQV8QVR0t76XD6wmFtXA,3
|
2
|
-
omlish/__about__.py,sha256=
|
2
|
+
omlish/__about__.py,sha256=G5PhHDsjnmH0v-N3l7GO0RtaA0iLAw7M9ihGEGPM0x4,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
|
@@ -7,32 +7,33 @@ omlish/cached.py,sha256=UAizxlH4eMWHPzQtmItmyE6FEpFEUFzIkxaO2BHWZ5s,196
|
|
7
7
|
omlish/check.py,sha256=3qp1_W8uRp23I26nWvG_c7YFxdTwJAZEFxmY8Bfw50Y,10078
|
8
8
|
omlish/datetimes.py,sha256=HajeM1kBvwlTa-uR1TTZHmZ3zTPnnUr1uGGQhiO1XQ0,2152
|
9
9
|
omlish/defs.py,sha256=T3bq_7h_tO3nDB5RAFBn7DkdeQgqheXzkFColbOHZko,4890
|
10
|
-
omlish/docker.py,sha256=
|
10
|
+
omlish/docker.py,sha256=uRVJUJwGtTFYhm4XeztrVEYk93f0NI5VpjEKQaN_5uY,6453
|
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
|
-
omlish/matchfns.py,sha256=
|
17
|
+
omlish/matchfns.py,sha256=I1IlQGfEyk_AcFSy6ulVS3utC-uwyZM2YfUXYHc9Bw0,6152
|
17
18
|
omlish/multiprocessing.py,sha256=QZT4C7I-uThCAjaEY3xgUYb-5GagUlnE4etN01LDyU4,5186
|
18
|
-
omlish/os.py,sha256=
|
19
|
+
omlish/os.py,sha256=vO1sZCzAhVxo46tDFLrD52q2KuMFWQwu5MPJgSsnliI,3107
|
19
20
|
omlish/runmodule.py,sha256=PWvuAaJ9wQQn6bx9ftEL3_d04DyotNn8dR_twm2pgw0,700
|
20
21
|
omlish/sync.py,sha256=AqwIfIuCMVHLwlJUa7dmaSjfA4sM5AYPCD5-nsz3XVQ,1516
|
21
22
|
omlish/term.py,sha256=NEmxqAhicyInGtmFamZAizI2xdu819MzFYPEp0Fx97M,6111
|
22
23
|
omlish/asyncs/__init__.py,sha256=uUz9ziKh4_QrgmdhKFMgq6j7mFbiZd3LiogguDCQsGI,587
|
23
|
-
omlish/asyncs/anyio.py,sha256=
|
24
|
+
omlish/asyncs/anyio.py,sha256=gfpx-D8QGmUfhnQxHEaHXcAP8zSMQjcGw4COFTGNnHI,8021
|
24
25
|
omlish/asyncs/asyncio.py,sha256=JfM59QgB3asgEbrps0zoVbNjWD4kL2XdsEkRMEIoFos,971
|
25
26
|
omlish/asyncs/asyncs.py,sha256=Tf7ZodTGepkM7HAuFcDNh9lLzzrMw6rELWvopGmFkh4,2035
|
26
|
-
omlish/asyncs/bridge.py,sha256=
|
27
|
+
omlish/asyncs/bridge.py,sha256=bcTEhsBJOWAMixu_fCxkDedLP3NEitAfwaHYTu26sQE,8980
|
27
28
|
omlish/asyncs/flavors.py,sha256=1mNxGNRVmjUHzA13K5ht8vdJv4CLEmzYTQ6BZXr1520,4866
|
28
|
-
omlish/asyncs/trio.py,sha256=
|
29
|
+
omlish/asyncs/trio.py,sha256=fmZ5b_lKdVV8NQ3euCUutWgnkqTFzSnOjvJSA_jvmrE,367
|
29
30
|
omlish/asyncs/trio_asyncio.py,sha256=oqdOHy0slj9PjVxaDf3gJkq9AAgg7wYZbB469jOftVw,1327
|
30
31
|
omlish/bootstrap/__init__.py,sha256=-Rtsg7uPQNhh1dIT9nqrz96XlqizwoLnWf-FwOEstJI,730
|
31
32
|
omlish/bootstrap/__main__.py,sha256=d23loR_cKfTYZwYiqpt_CmKI7dd5WcYFgIYzqMep75E,68
|
32
33
|
omlish/bootstrap/base.py,sha256=koELbK6UmsZaRj-6Bng5_zPVmEBqDpFCduEdR5BddOs,1077
|
33
34
|
omlish/bootstrap/diag.py,sha256=x_BKS_uhfW8QFk1NeH_VIocHif-A6FVTZ37262qCgZ0,5052
|
34
35
|
omlish/bootstrap/harness.py,sha256=pIeSXKfMsF7-3ZkU0gGpde-PtLAKKcVrWaxcin7Xzy0,2041
|
35
|
-
omlish/bootstrap/main.py,sha256=
|
36
|
+
omlish/bootstrap/main.py,sha256=u-TfxO4GkAK3LbRweQERogtO4kT0z3gqXRjnXvtJzC8,5328
|
36
37
|
omlish/bootstrap/marshal.py,sha256=qKewGVs-3i2p5W9nywkXSo1pcbVxmOAlTvfLjyo0xpo,554
|
37
38
|
omlish/bootstrap/sys.py,sha256=U0MFxO9tLFV3cdN5Y-Zrink6_45sFvzPUYQXyBk7-ns,8741
|
38
39
|
omlish/collections/__init__.py,sha256=tGUzvS_ZjiqALsLRy7JX3h4KZRQX2CmtdAfTRD7UwMk,1677
|
@@ -59,7 +60,7 @@ omlish/collections/cache/types.py,sha256=yNjwd6CGyTJQdxN2CQxFqqBAlcs1Z7vvNV-aU1K
|
|
59
60
|
omlish/concurrent/__init__.py,sha256=9p-s8MvBEYDqHIoYU3OYoe-Nni22QdkW7nhZGEukJTM,197
|
60
61
|
omlish/concurrent/executors.py,sha256=FYKCDYYuj-OgMa8quLsA47SfFNX3KDJvRENVk8NDsrA,1292
|
61
62
|
omlish/concurrent/futures.py,sha256=J2s9wYURUskqRJiBbAR0PNEAp1pXbIMYldOVBTQduQY,4239
|
62
|
-
omlish/concurrent/threadlets.py,sha256=
|
63
|
+
omlish/concurrent/threadlets.py,sha256=0fl0_Q_joTLtFYhR2kpKu45BW-win-le0rCuXPBtjko,2382
|
63
64
|
omlish/configs/__init__.py,sha256=3uh09ezodTwkMI0nRmAMP0eEuJ_0VdF-LYyNmPjHiCE,77
|
64
65
|
omlish/configs/classes.py,sha256=GLbB8xKjHjjoUQRCUQm3nEjM8z1qNTx9gPV7ODSt5dg,1317
|
65
66
|
omlish/configs/flattening.py,sha256=AOlRpBHm449MxwMp3CiIRGunStOC1DUNs1f3CLou0wc,4731
|
@@ -101,7 +102,7 @@ omlish/diag/threads.py,sha256=1-x02VCDZ407gfbtXm1pWK-ubqhqfePm9PMqkHCVoqk,3642
|
|
101
102
|
omlish/diag/replserver/__init__.py,sha256=uLo6V2aQ29v9z3IMELlPDSlG3_2iOT4-_X8VniF-EgE,235
|
102
103
|
omlish/diag/replserver/__main__.py,sha256=LmU41lQ58bm1h4Mx7S8zhE_uEBSC6kPcp9mn5JRpulA,32
|
103
104
|
omlish/diag/replserver/console.py,sha256=XzBDVhYlr8FY6ym4OwoaIHuFOHnGK3dTYlMDIOMUUlA,7410
|
104
|
-
omlish/diag/replserver/server.py,sha256=
|
105
|
+
omlish/diag/replserver/server.py,sha256=5pRjBn-Vz8gtu45756ycdbJe58C_xrB9rElPytr6h5g,5345
|
105
106
|
omlish/dispatch/__init__.py,sha256=GsiGJ91NKiQptSROtnCSkrZExBkvfDwYvdoTu5dBqF0,117
|
106
107
|
omlish/dispatch/_dispatch2.py,sha256=v3tCNyxGpOwY8qTwdp54TlM8mG6OVwtQoUZfYJ_griU,1756
|
107
108
|
omlish/dispatch/_dispatch3.py,sha256=Vnu5DfoPWFJLodudBqoZBXGTi2wYk-Az56MXJgdQvwc,2608
|
@@ -130,7 +131,7 @@ omlish/http/cookies.py,sha256=uuOYlHR6e2SC3GM41V0aozK10nef9tYg83Scqpn5-HM,6351
|
|
130
131
|
omlish/http/dates.py,sha256=Otgp8wRxPgNGyzx8LFowu1vC4EKJYARCiAwLFncpfHM,2875
|
131
132
|
omlish/http/encodings.py,sha256=w2WoKajpaZnQH8j-IBvk5ZFL2O2pAU_iBvZnkocaTlw,164
|
132
133
|
omlish/http/json.py,sha256=9XwAsl4966Mxrv-1ytyCqhcE6lbBJw-0_tFZzGszgHE,7440
|
133
|
-
omlish/http/sessions.py,sha256=
|
134
|
+
omlish/http/sessions.py,sha256=VZ_WS5uiQG5y7i3u8oKuQMqf8dPKUOjFm_qk_0OvI8c,4793
|
134
135
|
omlish/http/wsgi.py,sha256=czZsVUX-l2YTlMrUjKN49wRoP4rVpS0qpeBn4O5BoMY,948
|
135
136
|
omlish/inject/__init__.py,sha256=JQ7x8l9MjU-kJ5ap7cPVq7SY7zbbCIrjyJAF0UeE5-s,1886
|
136
137
|
omlish/inject/binder.py,sha256=H8AQ4ecmBOtDL8fMgrU1yUJl1gBADLNcdysRbvO8Wso,4167
|
@@ -162,11 +163,11 @@ omlish/inject/impl/privates.py,sha256=alpCYyk5VJ9lJknbRH2nLVNFYVvFhkj-VC1Vco3zCF
|
|
162
163
|
omlish/inject/impl/providers.py,sha256=QnwhsujJFIHC0JTgd2Wlo1kP53i3CWTrj1nKU2DNxwg,2375
|
163
164
|
omlish/inject/impl/proxy.py,sha256=1ko0VaKqzu9UG8bIldp9xtUrAVUOFTKWKTjOCqIGr4s,1636
|
164
165
|
omlish/inject/impl/scopes.py,sha256=ASfULXgP_ETlsAqFJfrZmyEaZt64Zr8tNn5ScA-EoXk,5900
|
165
|
-
omlish/lang/__init__.py,sha256=
|
166
|
+
omlish/lang/__init__.py,sha256=0OCNjiSSyFL3RSNtakj0ILhC1K2P2WJkDTAgkC7xMjA,3601
|
166
167
|
omlish/lang/cached.py,sha256=LwsgWQjQ5op618rBvI8vbASOEGWDTt_SKq6Tc1vlgZM,7680
|
167
168
|
omlish/lang/clsdct.py,sha256=AjtIWLlx2E6D5rC97zQ3Lwq2SOMkbg08pdO_AxpzEHI,1744
|
168
169
|
omlish/lang/cmp.py,sha256=5vbzWWbqdzDmNKAGL19z6ZfUKe5Ci49e-Oegf9f4BsE,1346
|
169
|
-
omlish/lang/contextmanagers.py,sha256=
|
170
|
+
omlish/lang/contextmanagers.py,sha256=NEwaTLQMfhKawD5x_0HgI2RpeLXbMa5r9NqWqfDnUXI,10408
|
170
171
|
omlish/lang/datetimes.py,sha256=ehI_DhQRM-bDxAavnp470XcekbbXc4Gdw9y1KpHDJT0,223
|
171
172
|
omlish/lang/descriptors.py,sha256=OLM1qi14kY7PLGIJnvkd6CBEOzHgD9q8Cs2cB6Kzflk,6602
|
172
173
|
omlish/lang/exceptions.py,sha256=qJBo3NU1mOWWm-NhQUHCY5feYXR3arZVyEHinLsmRH4,47
|
@@ -176,13 +177,13 @@ omlish/lang/iterables.py,sha256=_q6rHbdFfW3VBqez0IV3rUABoNxsA_oBv_sykm5zsbQ,2243
|
|
176
177
|
omlish/lang/maybes.py,sha256=NYHZDjqDtwPMheDrj2VtUVujxRPf8Qpgk4ZlZCTvBZc,3492
|
177
178
|
omlish/lang/objects.py,sha256=1dY8dX5voIZf5FBYUiN0BRsWg2JCdsgRbDl9fLG7OtY,4310
|
178
179
|
omlish/lang/resolving.py,sha256=OuN2mDTPNyBUbcrswtvFKtj4xgH4H4WglgqSKv3MTy0,1606
|
179
|
-
omlish/lang/resources.py,sha256
|
180
|
-
omlish/lang/strings.py,sha256=
|
180
|
+
omlish/lang/resources.py,sha256=-NmVTrSMKFZ6smVfOMz46ekZYVGgYh8cPooxQlFpG6s,2135
|
181
|
+
omlish/lang/strings.py,sha256=LqxR49cF5owHKpbUX8nUIBPsZ-4w7xqHPhlB-HIWqUg,3628
|
181
182
|
omlish/lang/sys.py,sha256=UoZz_PJYVKLQAKqYxxn-LHz1okK_38I__maZgnXMcxU,406
|
182
183
|
omlish/lang/timeouts.py,sha256=vECdWYhc_IZgcal1Ng1Y42wf2FV3KAx-i8As-MgGHIQ,1186
|
183
184
|
omlish/lang/typing.py,sha256=lJ2NGe4Pmb61I0Tx4A_rOqXNFTws1XHOzafg2knRUio,4155
|
184
185
|
omlish/lang/classes/__init__.py,sha256=h9QXrvAKD17_pIog0uF-7BCqZbSpJZYxL7kzVzvljp0,583
|
185
|
-
omlish/lang/classes/abstract.py,sha256=
|
186
|
+
omlish/lang/classes/abstract.py,sha256=IRnjuLLNwpxvEJsp8fwoQdCIpw0MDAd0TiQfoDMgsn4,2306
|
186
187
|
omlish/lang/classes/restrict.py,sha256=pSK7ZT_kpwqS6lWRrxwuEe-tt07F0-uZVazgGh-HDco,3921
|
187
188
|
omlish/lang/classes/simple.py,sha256=JkWYrRWnSKil6kVMgXgRMJeCxkFHXQIKIzYtG1jK2Pk,3067
|
188
189
|
omlish/lang/classes/virtual.py,sha256=W-QJuKsDehOcrydwg6eMN0bFPTYbk3Tz84TSH3blb44,3367
|
@@ -199,7 +200,7 @@ omlish/lite/cached.py,sha256=dUm647FbIsoxWT23XUFM51F7i-C2Buxr5b5zzgbCtQI,546
|
|
199
200
|
omlish/lite/check.py,sha256=DYxkYkxpnQpjGpDwW_8M8YBXbswvnBUCr0UBPU7aNKo,642
|
200
201
|
omlish/lite/contextmanagers.py,sha256=HnQJiyrOmSvTL22XRJrFl5CLpCyHD9fsntEUAr9G-60,427
|
201
202
|
omlish/lite/json.py,sha256=7-02Ny4fq-6YAu5ynvqoijhuYXWpLmfCI19GUeZnb1c,740
|
202
|
-
omlish/lite/logs.py,sha256=
|
203
|
+
omlish/lite/logs.py,sha256=vkFkSX0Izb2P-NNMqqNLSec0BzeLOtHoQWgdXwQuDPU,6007
|
203
204
|
omlish/lite/marshal.py,sha256=u6jYUN_AndvI6__HJBvSw5ElHWC0CfHqgiDS28Vpqjg,8593
|
204
205
|
omlish/lite/reflect.py,sha256=9QYJwdINraq1JNMEgvoqeSlVvRRgOXpxAkpgX8EgRXc,1307
|
205
206
|
omlish/lite/runtime.py,sha256=VUhmNQvwf8QzkWSKj4Q0ReieJA_PzHaJNRBivfTseow,452
|
@@ -211,7 +212,7 @@ omlish/logs/_abc.py,sha256=UgrCUQVUi_PvT3p1CEkb3P74CFrFcZq2AFby3GEUv9M,5974
|
|
211
212
|
omlish/logs/configs.py,sha256=EE0jlNaXJbGnM7V-y4xS5VwyTBSTzFzc0BYaVjg0JmA,1283
|
212
213
|
omlish/logs/formatters.py,sha256=q79nMnR2mRIStPyGrydQHpYTXgC5HHptt8lH3W2Wwbs,671
|
213
214
|
omlish/logs/handlers.py,sha256=nyuFgmO05By_Xwq7es58ClzS51-F53lJL7gD0x5IqAg,228
|
214
|
-
omlish/logs/noisy.py,sha256=
|
215
|
+
omlish/logs/noisy.py,sha256=Ubc-eTH6ZbGYsLfUUi69JAotwuUwzb-SJBeGo_0dIZI,348
|
215
216
|
omlish/logs/utils.py,sha256=MgGovbP0zUrZ3FGD3qYNQWn-l0jy0Y0bStcQvv5BOmQ,391
|
216
217
|
omlish/marshal/__init__.py,sha256=RkZGfdp7x9KU8nEpb8hYBGANK-P_9AXMyjBXCrdYMmc,1757
|
217
218
|
omlish/marshal/any.py,sha256=e82OyYK3Emm1P1ClnsnxP7fIWC2iNVyW0H5nK4mLmWM,779
|
@@ -228,11 +229,11 @@ omlish/marshal/helpers.py,sha256=YA0pNo-Fkc-_qKeoRNXUpP36js8oelU7uENkvoGD4hY,120
|
|
228
229
|
omlish/marshal/iterables.py,sha256=6I_ZdJemLSQtJ4J5NrB9wi-eyxiJZS61HzHXp1yeiX8,2592
|
229
230
|
omlish/marshal/mappings.py,sha256=zhLtyot7tzQtBNj7C4RBxjMELxA5r2q2Mth8Br7xkFs,2803
|
230
231
|
omlish/marshal/maybes.py,sha256=tKkVsJATERgbVcEfBnsHBK_2_LCQIVyBzca-cA-9KH0,2112
|
231
|
-
omlish/marshal/naming.py,sha256=
|
232
|
+
omlish/marshal/naming.py,sha256=lIklR_Od4x1ghltAgOzqcKhHs-leeSv2YmFhCHO7GIs,613
|
232
233
|
omlish/marshal/numbers.py,sha256=oY_yMNJEnJhjfLh89gpPXvKqeUyhQcaTcQB6ecyHiG8,1704
|
233
234
|
omlish/marshal/objects.py,sha256=R-NPCT1-UZhONTnrsrAvZvAtM2qyQsKZ8CPLfqkSg5g,4494
|
234
235
|
omlish/marshal/optionals.py,sha256=r0XB5rqfasvgZJNrKYd6Unq2U4nHt3JURi26j0dYHlw,1499
|
235
|
-
omlish/marshal/polymorphism.py,sha256=
|
236
|
+
omlish/marshal/polymorphism.py,sha256=doA8aLUhna6aco5b2Ok3jsem1V4NsF3rM5RTfJt0a7U,5708
|
236
237
|
omlish/marshal/primitives.py,sha256=wcvcs5GH_TWVmzAszh3dvyKibJgBxnXke-AlAXiwrrI,1107
|
237
238
|
omlish/marshal/registries.py,sha256=GI2KogcxawMkk02Ky7-TsnijChoe1I7YTOPIbUNwSAI,1665
|
238
239
|
omlish/marshal/standard.py,sha256=uQZIGiCwihmhB1tmhpKnZWZly0DDkdGjCnN0d41WHho,2985
|
@@ -256,7 +257,7 @@ omlish/secrets/openssl.py,sha256=wxA_wIlxtuOUy71ABxAJgavh-UI_taOfm-A0dVlmSwM,621
|
|
256
257
|
omlish/secrets/passwords.py,sha256=3r-vEK6Gp6aq4L5Csnd06QnrjO9xfzHJP-g_7I9W_ao,4101
|
257
258
|
omlish/secrets/secrets.py,sha256=ClD7t_mkmWkseVk4ahLzYLuLXeTxiwwPiidYm42vLh4,6871
|
258
259
|
omlish/secrets/subprocesses.py,sha256=EcnKlHHtnUMHGrBWXDfu8tv28wlgZx4P4GOiuPW9Vo8,1105
|
259
|
-
omlish/specs/__init__.py,sha256=
|
260
|
+
omlish/specs/__init__.py,sha256=_CSPXx25uGhXkmqLs9CSdcWAkZaQnc3cJk3lb2dadgE,88
|
260
261
|
omlish/specs/jsonschema/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
261
262
|
omlish/specs/jsonschema/types.py,sha256=qoxExgKfrI-UZXdk3qcVZIEyp1WckFbb85_eGInEoAY,467
|
262
263
|
omlish/specs/jsonschema/keywords/__init__.py,sha256=Zt2g1BXd654uU2AQ5P7_-x2Wrtf6cNbP9mxI1wGN4wo,596
|
@@ -279,15 +280,16 @@ omlish/specs/jsonschema/schemas/draft202012/vocabularies/format.json,sha256=UOu_
|
|
279
280
|
omlish/specs/jsonschema/schemas/draft202012/vocabularies/meta-data.json,sha256=j3bW4U9Bubku-TO3CM3FFEyLUmhlGtEZGEhfsXVPHHY,892
|
280
281
|
omlish/specs/jsonschema/schemas/draft202012/vocabularies/unevaluated.json,sha256=Lb-8tzmUtnCwl2SSre4f_7RsIWgnhNL1pMpWH54tDLQ,506
|
281
282
|
omlish/specs/jsonschema/schemas/draft202012/vocabularies/validation.json,sha256=cBCjHlQfMtK-ch4t40jfdcmzaHaj7TBId_wKvaHTelg,2834
|
282
|
-
omlish/sql/__init__.py,sha256=
|
283
|
+
omlish/sql/__init__.py,sha256=TpZLsEJKJzvJ0eMzuV8hwOJJbkxBCV1RZPUMLAVB6io,173
|
283
284
|
omlish/sql/_abc.py,sha256=HLhnnLZ7l0r_N99I-RCqJe6VHth-9iluU7cR-7-5jfs,1519
|
284
|
-
omlish/sql/asyncs.py,sha256=Wye3dwh7oZEGYz2Y4DZQSHtW4xjI2AH5qjW-BSS2IfU,3688
|
285
285
|
omlish/sql/dbs.py,sha256=lpdFmm2vTwLoBiVYGj9yPsVcTEYYNCxlYZZpjfChzkY,1870
|
286
|
-
omlish/sql/duckdb.py,sha256=Z3wiZEn_21Lu1ElFRX0ATzoBMCw0KJxINjTRuTexYGM,3748
|
287
|
-
omlish/sql/exprs.py,sha256=gO4Fj4xEY-PuDgV-N8hBMy55glZz7O-4H7v1LWabfZY,323
|
288
286
|
omlish/sql/qualifiedname.py,sha256=rlW3gVmyucJbqwcxj_7BfK4X2HoXrMroZT2H45zPgJQ,2264
|
289
|
-
omlish/sql/
|
290
|
-
omlish/sql/
|
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
|
291
293
|
omlish/testing/__init__.py,sha256=kfiF10ykrjWXniedIl3g8j3pNAFyuSbp1D3ZXug3-Eo,168
|
292
294
|
omlish/testing/testing.py,sha256=pJUbZ0ymdrQoNG9r9UlGXypeU1x9ntEp9xcYBnyOHUs,3088
|
293
295
|
omlish/testing/pytest/__init__.py,sha256=b6ObMEHTZnvGEI_de6nN1x5FyitV6B2mNYkurA4Q7fo,336
|
@@ -297,7 +299,7 @@ omlish/testing/pytest/inject/__init__.py,sha256=pdRKv1HcDmJ_yArKJbYITPXXZthRSGgB
|
|
297
299
|
omlish/testing/pytest/inject/harness.py,sha256=sMKjP2EWHq-eeTB1YVXcANli2Czxt56_9ERg4HtkVPg,5810
|
298
300
|
omlish/testing/pytest/plugins/__init__.py,sha256=ys1zXrYrNm7Uo6YOIVJ6Bd3dQo6kv387k7MbTYlqZSI,467
|
299
301
|
omlish/testing/pytest/plugins/_registry.py,sha256=IK04KlBgiOJxKAyCCgjpX2R-9tE-btalYJkgjLc8Te8,77
|
300
|
-
omlish/testing/pytest/plugins/asyncs.py,sha256=
|
302
|
+
omlish/testing/pytest/plugins/asyncs.py,sha256=SV6oKCy50CGkzLGYX-CT4MfWNqsrH8ONEbIWC3tFcHA,5324
|
301
303
|
omlish/testing/pytest/plugins/depskip.py,sha256=xithY-OMtjwhv8mcRNkv-WI_PSQtHldQ8H1s60MIXkk,2673
|
302
304
|
omlish/testing/pytest/plugins/logging.py,sha256=1zs6Xe54wiaSjabCviaFXwKkoN97CKm3mA5mEoUeJGs,380
|
303
305
|
omlish/testing/pytest/plugins/managermarks.py,sha256=pDEcCNdDAcTS4jjZHSnAfmzqMJDBcJcSsM3QNhbJ6Gs,1485
|
@@ -305,7 +307,7 @@ omlish/testing/pytest/plugins/pydevd.py,sha256=u1fxfCgFw4wGKBkMV_H_l9WI8JoUwlRff
|
|
305
307
|
omlish/testing/pytest/plugins/repeat.py,sha256=flSQzE9GFOWksVKz-mUGnpxJpv3yRqn1G4K8pW7JHs0,498
|
306
308
|
omlish/testing/pytest/plugins/skips.py,sha256=EoZDg1uWccgbAegmzqI85c7RliycD1e2J4Y7vfDRhwM,1041
|
307
309
|
omlish/testing/pytest/plugins/spacing.py,sha256=JQQhi9q3c523Ro1a_K_9RGAb7HotiO74N8bYX2VESFE,707
|
308
|
-
omlish/testing/pytest/plugins/switches.py,sha256=
|
310
|
+
omlish/testing/pytest/plugins/switches.py,sha256=hqFYM6tCcr-6fAPg8DBI-TJn762Kq4EUFt6gjXgiAQQ,3802
|
309
311
|
omlish/testing/pytest/plugins/utils.py,sha256=L5C622UXcA_AUKDcvyh5IMiRfqSGGz0McdhwZWvfMlU,261
|
310
312
|
omlish/text/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
311
313
|
omlish/text/asdl.py,sha256=3v5UocAfxan_d9drkGNdH3AMfx_FFBpQu3ULGL4M6VM,16865
|
@@ -313,8 +315,8 @@ omlish/text/delimit.py,sha256=ubPXcXQmtbOVrUsNh5gH1mDq5H-n1y2R4cPL5_DQf68,4928
|
|
313
315
|
omlish/text/glyphsplit.py,sha256=Ug-dPRO7x-OrNNr8g1y6DotSZ2KH0S-VcOmUobwa4B0,3296
|
314
316
|
omlish/text/indent.py,sha256=6Jj6TFY9unaPa4xPzrnZemJ-fHsV53IamP93XGjSUHs,1274
|
315
317
|
omlish/text/parts.py,sha256=7vPF1aTZdvLVYJ4EwBZVzRSy8XB3YqPd7JwEnNGGAOo,6495
|
316
|
-
omlish-0.0.0.
|
317
|
-
omlish-0.0.0.
|
318
|
-
omlish-0.0.0.
|
319
|
-
omlish-0.0.0.
|
320
|
-
omlish-0.0.0.
|
318
|
+
omlish-0.0.0.dev31.dist-info/LICENSE,sha256=B_hVtavaA8zCYDW99DYdcpDLKz1n3BBRjZrcbv8uG8c,1451
|
319
|
+
omlish-0.0.0.dev31.dist-info/METADATA,sha256=ONRqZOyFknW_WO5Hntonm5hY10yIlv645eKTmoXhhyY,3694
|
320
|
+
omlish-0.0.0.dev31.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
|
321
|
+
omlish-0.0.0.dev31.dist-info/top_level.txt,sha256=pePsKdLu7DvtUiecdYXJ78iO80uDNmBlqe-8hOzOmfs,7
|
322
|
+
omlish-0.0.0.dev31.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|