omlish 0.0.0.dev2__py3-none-any.whl → 0.0.0.dev4__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.
Potentially problematic release.
This version of omlish might be problematic. Click here for more details.
- omlish/__about__.py +1 -2
- omlish/__init__.py +8 -0
- omlish/argparse.py +4 -4
- omlish/asyncs/__init__.py +23 -2
- omlish/asyncs/anyio.py +13 -11
- omlish/asyncs/asyncs.py +1 -3
- omlish/asyncs/flavors.py +201 -0
- omlish/asyncs/futures.py +10 -9
- omlish/asyncs/trio_asyncio.py +41 -0
- omlish/c3.py +1 -1
- omlish/check.py +3 -3
- omlish/collections/_abc.py +2 -0
- omlish/collections/_io_abc.py +4 -2
- omlish/collections/cache/__init__.py +1 -1
- omlish/collections/cache/descriptor.py +8 -8
- omlish/collections/cache/impl.py +24 -17
- omlish/collections/cache/types.py +1 -1
- omlish/collections/coerce.py +1 -1
- omlish/collections/frozen.py +6 -6
- omlish/collections/identity.py +3 -4
- omlish/collections/mappings.py +2 -2
- omlish/collections/ordered.py +7 -7
- omlish/collections/skiplist.py +1 -1
- omlish/collections/sorted.py +1 -1
- omlish/collections/treap.py +25 -0
- omlish/collections/treapmap.py +57 -5
- omlish/collections/unmodifiable.py +9 -9
- omlish/collections/utils.py +1 -1
- omlish/configs/flattening.py +7 -6
- omlish/configs/props.py +3 -3
- omlish/dataclasses/__init__.py +1 -1
- omlish/dataclasses/impl/__init__.py +17 -1
- omlish/dataclasses/impl/api.py +10 -11
- omlish/dataclasses/impl/as_.py +4 -4
- omlish/dataclasses/impl/exceptions.py +1 -1
- omlish/dataclasses/impl/fields.py +7 -7
- omlish/dataclasses/impl/frozen.py +2 -2
- omlish/dataclasses/impl/init.py +5 -5
- omlish/dataclasses/impl/internals.py +1 -1
- omlish/dataclasses/impl/metaclass.py +1 -1
- omlish/dataclasses/impl/order.py +1 -1
- omlish/dataclasses/impl/replace.py +1 -1
- omlish/dataclasses/impl/repr.py +4 -4
- omlish/dataclasses/impl/utils.py +6 -6
- omlish/defs.py +13 -17
- omlish/{procfs.py → diag/procfs.py} +22 -24
- omlish/diag/ps.py +47 -0
- omlish/{replserver → diag/replserver}/console.py +18 -20
- omlish/{replserver → diag/replserver}/server.py +8 -8
- omlish/dispatch/dispatch.py +5 -8
- omlish/dispatch/functions.py +1 -1
- omlish/dispatch/methods.py +4 -5
- omlish/docker.py +1 -1
- omlish/dynamic.py +10 -10
- omlish/fnpairs.py +400 -0
- omlish/graphs/trees.py +13 -13
- omlish/inject/__init__.py +7 -7
- omlish/inject/elements.py +1 -1
- omlish/inject/exceptions.py +7 -7
- omlish/inject/impl/elements.py +17 -5
- omlish/inject/impl/injector.py +12 -10
- omlish/inject/impl/inspect.py +2 -2
- omlish/inject/impl/scopes.py +12 -11
- omlish/inject/proxy.py +5 -5
- omlish/iterators.py +19 -24
- omlish/json.py +143 -6
- omlish/lang/__init__.py +13 -4
- omlish/lang/cached.py +2 -5
- omlish/lang/classes/__init__.py +2 -2
- omlish/lang/classes/abstract.py +2 -2
- omlish/lang/classes/restrict.py +14 -14
- omlish/lang/classes/simple.py +1 -1
- omlish/lang/classes/virtual.py +5 -5
- omlish/lang/clsdct.py +1 -1
- omlish/lang/cmp.py +2 -2
- omlish/lang/contextmanagers.py +12 -14
- omlish/lang/descriptors.py +16 -4
- omlish/lang/exceptions.py +1 -1
- omlish/lang/functions.py +58 -22
- omlish/lang/imports.py +22 -27
- omlish/lang/iterables.py +2 -2
- omlish/lang/maybes.py +1 -0
- omlish/lang/objects.py +15 -9
- omlish/lang/resolving.py +1 -1
- omlish/lang/strings.py +1 -1
- omlish/lang/sys.py +7 -0
- omlish/lang/typing.py +3 -3
- omlish/libc.py +9 -5
- omlish/logs/_abc.py +5 -1
- omlish/logs/filters.py +2 -0
- omlish/logs/formatters.py +6 -2
- omlish/logs/utils.py +1 -1
- omlish/marshal/base.py +3 -3
- omlish/marshal/exceptions.py +1 -1
- omlish/marshal/global_.py +10 -4
- omlish/marshal/objects.py +1 -2
- omlish/marshal/registries.py +3 -3
- omlish/marshal/utils.py +2 -2
- omlish/marshal/values.py +1 -1
- omlish/math.py +9 -9
- omlish/reflect.py +3 -3
- omlish/sql/__init__.py +9 -0
- omlish/sql/asyncs.py +148 -0
- omlish/stats.py +4 -5
- omlish/term.py +1 -1
- omlish/testing/pydevd.py +28 -6
- omlish/testing/pytest/inject/harness.py +1 -1
- omlish/testing/pytest/plugins/pydevd.py +1 -1
- omlish/testing/pytest/plugins/switches.py +1 -1
- omlish/text/delimit.py +3 -6
- {omlish-0.0.0.dev2.dist-info → omlish-0.0.0.dev4.dist-info}/METADATA +4 -1
- omlish-0.0.0.dev4.dist-info/RECORD +195 -0
- {omlish-0.0.0.dev2.dist-info → omlish-0.0.0.dev4.dist-info}/WHEEL +1 -1
- omlish/lang/classes/test/test_abstract.py +0 -89
- omlish/lang/classes/test/test_restrict.py +0 -71
- omlish/lang/classes/test/test_simple.py +0 -58
- omlish/lang/classes/test/test_virtual.py +0 -72
- omlish-0.0.0.dev2.dist-info/RECORD +0 -193
- /omlish/{lang/classes/test → diag}/__init__.py +0 -0
- /omlish/{replserver → diag/replserver}/__init__.py +0 -0
- /omlish/{replserver → diag/replserver}/__main__.py +0 -0
- /omlish/sql/{_abcs.py → _abc.py} +0 -0
- {omlish-0.0.0.dev2.dist-info → omlish-0.0.0.dev4.dist-info}/LICENSE +0 -0
- {omlish-0.0.0.dev2.dist-info → omlish-0.0.0.dev4.dist-info}/top_level.txt +0 -0
omlish/lang/objects.py
CHANGED
|
@@ -9,18 +9,22 @@ T = ta.TypeVar('T')
|
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
def attr_repr(obj: ta.Any, *attrs: str) -> str:
|
|
12
|
-
return '
|
|
13
|
-
type(obj).__name__,
|
|
14
|
-
', '.join('%s=%r' % (attr, getattr(obj, attr)) for attr in attrs))
|
|
12
|
+
return f'{type(obj).__name__}({", ".join(f"{attr}={getattr(obj, attr)!r}" for attr in attrs)})'
|
|
15
13
|
|
|
16
14
|
|
|
17
15
|
def arg_repr(*args, **kwargs) -> str:
|
|
18
16
|
return ', '.join(*(
|
|
19
17
|
list(map(repr, args)) +
|
|
20
|
-
[f'{k}={
|
|
18
|
+
[f'{k}={v!r}' for k, v in kwargs.items()]
|
|
21
19
|
))
|
|
22
20
|
|
|
23
21
|
|
|
22
|
+
def opt_repr(obj: ta.Any) -> str | None:
|
|
23
|
+
if obj is None:
|
|
24
|
+
return None
|
|
25
|
+
return repr(obj)
|
|
26
|
+
|
|
27
|
+
|
|
24
28
|
##
|
|
25
29
|
|
|
26
30
|
|
|
@@ -29,7 +33,7 @@ def new_type(
|
|
|
29
33
|
bases: ta.Sequence[ta.Any],
|
|
30
34
|
namespace: ta.Mapping[str, ta.Any],
|
|
31
35
|
**kwargs,
|
|
32
|
-
) ->
|
|
36
|
+
) -> type:
|
|
33
37
|
return types.new_class(
|
|
34
38
|
name,
|
|
35
39
|
tuple(bases),
|
|
@@ -40,12 +44,12 @@ def new_type(
|
|
|
40
44
|
|
|
41
45
|
def super_meta(
|
|
42
46
|
super_meta: ta.Any,
|
|
43
|
-
meta:
|
|
47
|
+
meta: type,
|
|
44
48
|
name: str,
|
|
45
49
|
bases: ta.Sequence[ta.Any],
|
|
46
50
|
namespace: ta.MutableMapping[str, ta.Any],
|
|
47
51
|
**kwargs,
|
|
48
|
-
) ->
|
|
52
|
+
) -> type:
|
|
49
53
|
"""Per types.new_class"""
|
|
50
54
|
resolved_bases = types.resolve_bases(bases)
|
|
51
55
|
if resolved_bases is not bases:
|
|
@@ -75,19 +79,21 @@ class SimpleProxy(ta.Generic[T]):
|
|
|
75
79
|
if instance is None:
|
|
76
80
|
return self
|
|
77
81
|
setattr(object.__getattribute__(instance, '__wrapped__'), self._attr, value)
|
|
82
|
+
return None
|
|
78
83
|
|
|
79
84
|
def __delete__(self, instance):
|
|
80
85
|
if instance is None:
|
|
81
86
|
return self
|
|
82
87
|
delattr(object.__getattribute__(instance, '__wrapped__'), self._attr)
|
|
88
|
+
return None
|
|
83
89
|
|
|
84
|
-
__wrapped_attrs__: ta.Iterable[str] =
|
|
90
|
+
__wrapped_attrs__: ta.ClassVar[ta.Iterable[str]] = ()
|
|
85
91
|
|
|
86
92
|
def __init__(self, wrapped: T) -> None:
|
|
87
93
|
super().__init__()
|
|
88
94
|
object.__setattr__(self, '__wrapped__', wrapped)
|
|
89
95
|
|
|
90
|
-
def __init_subclass__(cls, **kwargs):
|
|
96
|
+
def __init_subclass__(cls, **kwargs: ta.Any) -> None:
|
|
91
97
|
super().__init_subclass__(**kwargs)
|
|
92
98
|
|
|
93
99
|
for attr in cls.__wrapped_attrs__:
|
omlish/lang/resolving.py
CHANGED
omlish/lang/strings.py
CHANGED
|
@@ -22,7 +22,7 @@ def camel_case(name: str) -> str:
|
|
|
22
22
|
|
|
23
23
|
def snake_case(name: str) -> str:
|
|
24
24
|
uppers: list[int | None] = [i for i, c in enumerate(name) if c.isupper()]
|
|
25
|
-
return '_'.join([name[l:r].lower() for l, r in zip([None
|
|
25
|
+
return '_'.join([name[l:r].lower() for l, r in zip([None, *uppers], [*uppers, None])]).strip('_')
|
|
26
26
|
|
|
27
27
|
|
|
28
28
|
def is_dunder(name: str) -> bool:
|
omlish/lang/sys.py
ADDED
omlish/lang/typing.py
CHANGED
|
@@ -37,13 +37,13 @@ def _update_wrapper_no_anns(wrapper, wrapped):
|
|
|
37
37
|
return wrapper
|
|
38
38
|
|
|
39
39
|
|
|
40
|
-
def typed_lambda(ret=_MISSING, **kw):
|
|
40
|
+
def typed_lambda(ret=_MISSING, **kw): # noqa
|
|
41
41
|
def inner(fn):
|
|
42
42
|
ns = {}
|
|
43
43
|
ns['__fn'] = fn
|
|
44
44
|
proto = ['def __lam(']
|
|
45
45
|
call = ['return __fn(']
|
|
46
|
-
pkw =
|
|
46
|
+
pkw = dict(kw)
|
|
47
47
|
for i, (n, t) in enumerate(pkw.items()):
|
|
48
48
|
if i:
|
|
49
49
|
call.append(', ')
|
|
@@ -69,7 +69,7 @@ def typed_lambda(ret=_MISSING, **kw):
|
|
|
69
69
|
return inner
|
|
70
70
|
|
|
71
71
|
|
|
72
|
-
def typed_partial(obj, **kw):
|
|
72
|
+
def typed_partial(obj, **kw): # noqa
|
|
73
73
|
for k in kw:
|
|
74
74
|
if k.startswith('__'):
|
|
75
75
|
raise NameError(k)
|
omlish/libc.py
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
# ruff: noqa: ANN201
|
|
2
|
+
# ruff: noqa: N801
|
|
3
|
+
# ruff: noqa: N802
|
|
4
|
+
|
|
1
5
|
import ctypes as ct
|
|
2
6
|
import errno
|
|
3
7
|
import platform
|
|
@@ -37,14 +41,14 @@ def lasterr() -> tuple[int, str]:
|
|
|
37
41
|
|
|
38
42
|
|
|
39
43
|
# int raise(int sig);
|
|
40
|
-
libc._raise = libc['raise'] # type: ignore
|
|
41
|
-
libc._raise.restype = ct.c_int
|
|
42
|
-
libc._raise.argtypes = [ct.c_int]
|
|
43
|
-
_raise = libc._raise
|
|
44
|
+
libc._raise = libc['raise'] # type: ignore # noqa
|
|
45
|
+
libc._raise.restype = ct.c_int # noqa
|
|
46
|
+
libc._raise.argtypes = [ct.c_int] # noqa
|
|
47
|
+
_raise = libc._raise # noqa
|
|
44
48
|
|
|
45
49
|
|
|
46
50
|
def sigtrap() -> None:
|
|
47
|
-
libc._raise(signal.SIGTRAP)
|
|
51
|
+
libc._raise(signal.SIGTRAP) # noqa
|
|
48
52
|
|
|
49
53
|
|
|
50
54
|
##
|
omlish/logs/_abc.py
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
# ruff: noqa: A002
|
|
2
|
+
# ruff: noqa: N802
|
|
3
|
+
# ruff: noqa: N815
|
|
4
|
+
|
|
1
5
|
import types
|
|
2
6
|
import typing as ta
|
|
3
7
|
|
|
@@ -181,7 +185,7 @@ class Logger(Filterer, ta.Protocol):
|
|
|
181
185
|
|
|
182
186
|
def log(self, level: Level, msg: str, *args: ta.Any, **kwargs: ta.Any) -> None: ...
|
|
183
187
|
|
|
184
|
-
def findCaller(self, stack_info: bool = False, stacklevel: int = 1) -> Caller: ...
|
|
188
|
+
def findCaller(self, stack_info: bool = False, stacklevel: int = 1) -> Caller: ...
|
|
185
189
|
|
|
186
190
|
def makeRecord(
|
|
187
191
|
self,
|
omlish/logs/filters.py
CHANGED
omlish/logs/formatters.py
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
|
+
# ruff: noqa: ANN201
|
|
2
|
+
# ruff: noqa: N802
|
|
3
|
+
|
|
1
4
|
import datetime
|
|
2
5
|
import logging
|
|
6
|
+
import typing as ta
|
|
3
7
|
|
|
4
8
|
from .. import json
|
|
5
9
|
from .. import term
|
|
@@ -20,7 +24,7 @@ class StandardLogFormatter(logging.Formatter):
|
|
|
20
24
|
|
|
21
25
|
class ColorLogFormatter(StandardLogFormatter):
|
|
22
26
|
|
|
23
|
-
LEVEL_COLORS = {
|
|
27
|
+
LEVEL_COLORS: ta.Mapping[int, term.SGRs.FG] = {
|
|
24
28
|
logging.WARNING: term.SGRs.FG.BRIGHT_YELLOW,
|
|
25
29
|
logging.ERROR: term.SGRs.FG.BRIGHT_RED,
|
|
26
30
|
logging.CRITICAL: term.SGRs.FG.BRIGHT_RED,
|
|
@@ -39,7 +43,7 @@ class ColorLogFormatter(StandardLogFormatter):
|
|
|
39
43
|
|
|
40
44
|
class JsonLogFormatter(logging.Formatter):
|
|
41
45
|
|
|
42
|
-
KEYS = {
|
|
46
|
+
KEYS: ta.Mapping[str, bool] = {
|
|
43
47
|
'name': False,
|
|
44
48
|
'msg': False,
|
|
45
49
|
'args': False,
|
omlish/logs/utils.py
CHANGED
omlish/marshal/base.py
CHANGED
|
@@ -81,7 +81,7 @@ from .. import check
|
|
|
81
81
|
from .. import collections as col
|
|
82
82
|
from .. import lang
|
|
83
83
|
from .. import reflect as rfl
|
|
84
|
-
from .exceptions import
|
|
84
|
+
from .exceptions import UnhandledTypeError
|
|
85
85
|
from .factories import Factory
|
|
86
86
|
from .factories import RecursiveTypeFactory
|
|
87
87
|
from .registries import Registry
|
|
@@ -152,7 +152,7 @@ class MarshalContext(BaseContext, lang.Final):
|
|
|
152
152
|
rty = rfl.type_(o)
|
|
153
153
|
if (m := check.not_none(self.factory)(self, rty)) is not None: # noqa
|
|
154
154
|
return m
|
|
155
|
-
raise
|
|
155
|
+
raise UnhandledTypeError(rty)
|
|
156
156
|
|
|
157
157
|
|
|
158
158
|
@dc.dataclass(frozen=True)
|
|
@@ -163,7 +163,7 @@ class UnmarshalContext(BaseContext, lang.Final):
|
|
|
163
163
|
rty = rfl.type_(o)
|
|
164
164
|
if (m := check.not_none(self.factory)(self, rty)) is not None: # noqa
|
|
165
165
|
return m
|
|
166
|
-
raise
|
|
166
|
+
raise UnhandledTypeError(rty)
|
|
167
167
|
|
|
168
168
|
|
|
169
169
|
##
|
omlish/marshal/exceptions.py
CHANGED
omlish/marshal/global_.py
CHANGED
|
@@ -1,8 +1,14 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
import typing as ta
|
|
2
|
+
|
|
3
3
|
from .base import MarshalContext
|
|
4
4
|
from .base import UnmarshalContext
|
|
5
|
+
from .registries import Registry
|
|
6
|
+
from .standard import new_standard_marshaler_factory
|
|
5
7
|
from .standard import new_standard_unmarshaler_factory
|
|
8
|
+
from .values import Value
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
T = ta.TypeVar('T')
|
|
6
12
|
|
|
7
13
|
|
|
8
14
|
##
|
|
@@ -17,7 +23,7 @@ GLOBAL_REGISTRY = Registry()
|
|
|
17
23
|
GLOBAL_MARSHALER_FACTORY = new_standard_marshaler_factory()
|
|
18
24
|
|
|
19
25
|
|
|
20
|
-
def marshal(obj, ty=None, **kwargs):
|
|
26
|
+
def marshal(obj: ta.Any, ty: type | None = None, **kwargs: ta.Any) -> Value:
|
|
21
27
|
mc = MarshalContext(GLOBAL_REGISTRY, factory=GLOBAL_MARSHALER_FACTORY, **kwargs)
|
|
22
28
|
return mc.make(ty if ty is not None else type(obj)).marshal(mc, obj)
|
|
23
29
|
|
|
@@ -28,6 +34,6 @@ def marshal(obj, ty=None, **kwargs):
|
|
|
28
34
|
GLOBAL_UNMARSHALER_FACTORY = new_standard_unmarshaler_factory()
|
|
29
35
|
|
|
30
36
|
|
|
31
|
-
def unmarshal(v, ty, **kwargs):
|
|
37
|
+
def unmarshal(v: Value, ty: type[T], **kwargs: ta.Any) -> T:
|
|
32
38
|
uc = UnmarshalContext(GLOBAL_REGISTRY, factory=GLOBAL_UNMARSHALER_FACTORY, **kwargs)
|
|
33
39
|
return uc.make(ty).unmarshal(uc, v)
|
omlish/marshal/objects.py
CHANGED
|
@@ -98,8 +98,7 @@ class ObjectUnmarshaler(Unmarshaler):
|
|
|
98
98
|
if ukf is not None:
|
|
99
99
|
ukf[ks] = mv # FIXME: unmarshal?
|
|
100
100
|
continue
|
|
101
|
-
|
|
102
|
-
raise
|
|
101
|
+
raise
|
|
103
102
|
if fi.name in kw:
|
|
104
103
|
raise KeyError(f'Duplicate keys for field {fi.name!r}: {ks!r}')
|
|
105
104
|
kw[fi.name] = u.unmarshal(ctx, mv)
|
omlish/marshal/registries.py
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import abc
|
|
2
1
|
import dataclasses as dc
|
|
3
2
|
import threading
|
|
4
3
|
import typing as ta
|
|
5
4
|
|
|
6
5
|
from .. import check
|
|
6
|
+
from .. import lang
|
|
7
7
|
from .. import reflect as rfl
|
|
8
8
|
|
|
9
9
|
|
|
10
|
-
class RegistryItem(
|
|
10
|
+
class RegistryItem(lang.Abstract):
|
|
11
11
|
pass
|
|
12
12
|
|
|
13
13
|
|
|
@@ -31,7 +31,7 @@ class Registry:
|
|
|
31
31
|
super().__init__()
|
|
32
32
|
self._mtx = threading.Lock()
|
|
33
33
|
self._dct: dict[rfl.Type, _TypeRegistry] = {}
|
|
34
|
-
self._ps: ta.Sequence[
|
|
34
|
+
self._ps: ta.Sequence[Registry] = []
|
|
35
35
|
|
|
36
36
|
def register(self, rty: rfl.Type, *items: RegistryItem) -> 'Registry':
|
|
37
37
|
check.isinstance(rty, rfl.TYPES)
|
omlish/marshal/utils.py
CHANGED
omlish/marshal/values.py
CHANGED
omlish/math.py
CHANGED
|
@@ -66,7 +66,7 @@ class FixedWidthInt(int):
|
|
|
66
66
|
|
|
67
67
|
MASK: ta.ClassVar[int]
|
|
68
68
|
|
|
69
|
-
def __init_subclass__(cls
|
|
69
|
+
def __init_subclass__(cls) -> None:
|
|
70
70
|
super().__init_subclass__()
|
|
71
71
|
|
|
72
72
|
if not isinstance(cls.BITS, int):
|
|
@@ -82,13 +82,13 @@ class FixedWidthInt(int):
|
|
|
82
82
|
cls.MASK = (1 << cls.BITS) - 1
|
|
83
83
|
|
|
84
84
|
@classmethod
|
|
85
|
-
def clamp(cls, value):
|
|
85
|
+
def clamp(cls, value: int) -> int:
|
|
86
86
|
return ((value - cls.MIN) & cls.MASK) + cls.MIN
|
|
87
87
|
|
|
88
|
-
def __new__(cls, value
|
|
89
|
-
return super().__new__(cls, cls.clamp(value))
|
|
88
|
+
def __new__(cls, value: int) -> 'FixedWidthInt':
|
|
89
|
+
return super().__new__(cls, cls.clamp(value)) # noqa
|
|
90
90
|
|
|
91
|
-
SCALAR_PROXY_METHODS =
|
|
91
|
+
SCALAR_PROXY_METHODS = frozenset([
|
|
92
92
|
'__abs__',
|
|
93
93
|
'__add__',
|
|
94
94
|
'__and__',
|
|
@@ -117,12 +117,12 @@ class FixedWidthInt(int):
|
|
|
117
117
|
'__sub__',
|
|
118
118
|
'__truediv__',
|
|
119
119
|
'__xor__',
|
|
120
|
-
|
|
120
|
+
])
|
|
121
121
|
|
|
122
|
-
TUPLE_PROXY_METHODS =
|
|
122
|
+
TUPLE_PROXY_METHODS = frozenset([
|
|
123
123
|
'__divmod__',
|
|
124
124
|
'__rdivmod__',
|
|
125
|
-
|
|
125
|
+
])
|
|
126
126
|
|
|
127
127
|
for _proxy_name in SCALAR_PROXY_METHODS:
|
|
128
128
|
locals()[_proxy_name] = _gen_scalar_proxy_method(_proxy_name)
|
|
@@ -130,7 +130,7 @@ class FixedWidthInt(int):
|
|
|
130
130
|
locals()[_proxy_name] = _gen_tuple_proxy_method(_proxy_name)
|
|
131
131
|
del _proxy_name
|
|
132
132
|
|
|
133
|
-
def __repr__(self):
|
|
133
|
+
def __repr__(self) -> str:
|
|
134
134
|
return f'{self.__class__.__name__}({int(self)})'
|
|
135
135
|
|
|
136
136
|
|
omlish/reflect.py
CHANGED
|
@@ -21,7 +21,7 @@ else:
|
|
|
21
21
|
|
|
22
22
|
_NoneType = types.NoneType # type: ignore
|
|
23
23
|
|
|
24
|
-
_NONE_TYPE_FROZENSET:
|
|
24
|
+
_NONE_TYPE_FROZENSET: frozenset['Type'] = frozenset([_NoneType])
|
|
25
25
|
|
|
26
26
|
|
|
27
27
|
_GenericAlias = ta._GenericAlias # type: ignore # noqa
|
|
@@ -99,7 +99,7 @@ Type = ta.Union[
|
|
|
99
99
|
|
|
100
100
|
|
|
101
101
|
class Union(ta.NamedTuple):
|
|
102
|
-
args:
|
|
102
|
+
args: frozenset[Type]
|
|
103
103
|
|
|
104
104
|
@property
|
|
105
105
|
def is_optional(self) -> bool:
|
|
@@ -121,7 +121,7 @@ class Generic(ta.NamedTuple):
|
|
|
121
121
|
# params2: tuple[ta.TypeVar, ...] # map[int, V] = (V,) | map[T, T] = (T,)
|
|
122
122
|
obj: ta.Any
|
|
123
123
|
|
|
124
|
-
def __repr__(self):
|
|
124
|
+
def __repr__(self) -> str:
|
|
125
125
|
return (
|
|
126
126
|
f'{self.__class__.__name__}('
|
|
127
127
|
f'cls={self.cls.__name__}, '
|
omlish/sql/__init__.py
CHANGED
omlish/sql/asyncs.py
ADDED
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
"""
|
|
2
|
+
TODO:
|
|
3
|
+
- Maysync impls?
|
|
4
|
+
- base Protocol so adapters and real sa impls can be used interchangeably (if in asyncio ctx)?
|
|
5
|
+
"""
|
|
6
|
+
import contextlib
|
|
7
|
+
import typing as ta
|
|
8
|
+
|
|
9
|
+
import sqlalchemy as sa
|
|
10
|
+
import sqlalchemy.ext.asyncio as saa
|
|
11
|
+
|
|
12
|
+
from .. import asyncs as au
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
T = ta.TypeVar('T')
|
|
16
|
+
P = ta.ParamSpec('P')
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
AsyncEngineLike = ta.Union[saa.AsyncEngine, 'AsyncEngine']
|
|
20
|
+
AsyncConnectionLike = ta.Union[saa.AsyncConnection, 'AsyncConnection']
|
|
21
|
+
AsyncTransactionLike = ta.Union[saa.AsyncTransaction, 'AsyncTransaction']
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class AsyncTransaction:
|
|
25
|
+
def __init__(self, underlying: saa.AsyncTransaction) -> None:
|
|
26
|
+
super().__init__()
|
|
27
|
+
self._underlying = underlying
|
|
28
|
+
|
|
29
|
+
@property
|
|
30
|
+
def underlying(self) -> saa.AsyncTransaction:
|
|
31
|
+
return self._underlying
|
|
32
|
+
|
|
33
|
+
##
|
|
34
|
+
|
|
35
|
+
@au.mark_asyncio
|
|
36
|
+
async def close(self) -> None:
|
|
37
|
+
await au.from_asyncio(self._underlying.close)()
|
|
38
|
+
|
|
39
|
+
@au.mark_asyncio
|
|
40
|
+
async def rollback(self) -> None:
|
|
41
|
+
await au.from_asyncio(self._underlying.rollback)()
|
|
42
|
+
|
|
43
|
+
@au.mark_asyncio
|
|
44
|
+
async def commit(self) -> None:
|
|
45
|
+
await au.from_asyncio(self._underlying.commit)()
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class AsyncConnection:
|
|
49
|
+
def __init__(self, underlying: saa.AsyncConnection) -> None:
|
|
50
|
+
super().__init__()
|
|
51
|
+
self._underlying = underlying
|
|
52
|
+
|
|
53
|
+
@property
|
|
54
|
+
def underlying(self) -> saa.AsyncConnection:
|
|
55
|
+
return self._underlying
|
|
56
|
+
|
|
57
|
+
##
|
|
58
|
+
|
|
59
|
+
@contextlib.asynccontextmanager
|
|
60
|
+
@au.mark_asyncio
|
|
61
|
+
async def begin(self) -> ta.AsyncIterator[AsyncTransaction]:
|
|
62
|
+
async with au.from_asyncio_context(self._underlying.begin()) as u:
|
|
63
|
+
yield AsyncTransaction(u)
|
|
64
|
+
|
|
65
|
+
@au.mark_asyncio
|
|
66
|
+
async def execute(
|
|
67
|
+
self,
|
|
68
|
+
statement: ta.Any,
|
|
69
|
+
*args: ta.Any,
|
|
70
|
+
**kwargs: ta.Any,
|
|
71
|
+
) -> sa.CursorResult[ta.Any]:
|
|
72
|
+
return await au.from_asyncio(self._underlying.execute)(statement, *args, **kwargs)
|
|
73
|
+
|
|
74
|
+
@au.mark_asyncio
|
|
75
|
+
async def run_sync(
|
|
76
|
+
self,
|
|
77
|
+
fn: ta.Callable[ta.Concatenate[sa.Connection, P], T],
|
|
78
|
+
*args: P.args,
|
|
79
|
+
**kwargs: P.kwargs,
|
|
80
|
+
) -> T:
|
|
81
|
+
return await au.from_asyncio(self._underlying.run_sync)(fn, *args, **kwargs)
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
class AsyncEngine:
|
|
85
|
+
def __init__(self, underlying: saa.AsyncEngine) -> None:
|
|
86
|
+
super().__init__()
|
|
87
|
+
self._underlying = underlying
|
|
88
|
+
|
|
89
|
+
@property
|
|
90
|
+
def underlying(self) -> saa.AsyncEngine:
|
|
91
|
+
return self._underlying
|
|
92
|
+
|
|
93
|
+
##
|
|
94
|
+
|
|
95
|
+
@contextlib.asynccontextmanager
|
|
96
|
+
@au.mark_asyncio
|
|
97
|
+
async def connect(self) -> ta.AsyncIterator[AsyncConnection]:
|
|
98
|
+
async with au.from_asyncio_context(self._underlying.connect()) as u:
|
|
99
|
+
yield AsyncConnection(u)
|
|
100
|
+
|
|
101
|
+
@au.mark_asyncio
|
|
102
|
+
async def dispose(self, close: bool = True) -> None:
|
|
103
|
+
await au.from_asyncio(self._underlying.dispose)(close)
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
##
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
@ta.overload
|
|
110
|
+
def async_adapt(obj: AsyncEngine) -> AsyncEngine:
|
|
111
|
+
...
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
@ta.overload
|
|
115
|
+
def async_adapt(obj: AsyncConnection) -> AsyncConnection:
|
|
116
|
+
...
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
@ta.overload
|
|
120
|
+
def async_adapt(obj: AsyncTransaction) -> AsyncTransaction:
|
|
121
|
+
...
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
@ta.overload
|
|
125
|
+
def async_adapt(obj: saa.AsyncEngine) -> AsyncEngine:
|
|
126
|
+
...
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
@ta.overload
|
|
130
|
+
def async_adapt(obj: saa.AsyncConnection) -> AsyncConnection:
|
|
131
|
+
...
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
@ta.overload
|
|
135
|
+
def async_adapt(obj: saa.AsyncTransaction) -> AsyncTransaction:
|
|
136
|
+
...
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
def async_adapt(obj: ta.Any) -> ta.Any:
|
|
140
|
+
if isinstance(obj, (AsyncEngine, AsyncConnection, AsyncTransaction)):
|
|
141
|
+
return obj
|
|
142
|
+
if isinstance(obj, saa.AsyncTransaction):
|
|
143
|
+
return AsyncTransaction(obj)
|
|
144
|
+
if isinstance(obj, saa.AsyncConnection):
|
|
145
|
+
return AsyncConnection(obj)
|
|
146
|
+
if isinstance(obj, saa.AsyncEngine):
|
|
147
|
+
return AsyncEngine(obj)
|
|
148
|
+
raise TypeError(obj)
|
omlish/stats.py
CHANGED
|
@@ -5,6 +5,7 @@ TODO:
|
|
|
5
5
|
"""
|
|
6
6
|
import bisect
|
|
7
7
|
import collections
|
|
8
|
+
import contextlib
|
|
8
9
|
import dataclasses as dc
|
|
9
10
|
import math
|
|
10
11
|
import operator
|
|
@@ -215,7 +216,7 @@ class Stats(ta.Sequence[float]):
|
|
|
215
216
|
else:
|
|
216
217
|
bins = [float(x) for x in bins]
|
|
217
218
|
if self.min < bins[0]:
|
|
218
|
-
bins = [self.min
|
|
219
|
+
bins = [self.min, *bins]
|
|
219
220
|
|
|
220
221
|
round_factor = 10.0 ** bin_digits
|
|
221
222
|
bins = [math.floor(b * round_factor) / round_factor for b in bins]
|
|
@@ -251,7 +252,7 @@ class SamplingHistogram:
|
|
|
251
252
|
sample_percentiles: list['SamplingHistogram.Percentile']
|
|
252
253
|
|
|
253
254
|
DEFAULT_SIZE = 1000
|
|
254
|
-
DEFAULT_PERCENTILES =
|
|
255
|
+
DEFAULT_PERCENTILES = (0.5, 0.75, 0.9, 0.95, 0.99)
|
|
255
256
|
|
|
256
257
|
def __init__(
|
|
257
258
|
self,
|
|
@@ -291,10 +292,8 @@ class SamplingHistogram:
|
|
|
291
292
|
|
|
292
293
|
sample_pos = None
|
|
293
294
|
if self._sample_pos_queue:
|
|
294
|
-
|
|
295
|
+
with contextlib.suppress(IndexError):
|
|
295
296
|
sample_pos = self._sample_pos_queue.pop()
|
|
296
|
-
except IndexError:
|
|
297
|
-
pass
|
|
298
297
|
if sample_pos is None:
|
|
299
298
|
sample_pos = random.randrange(0, self._size)
|
|
300
299
|
self._sample[sample_pos] = entry
|