omlish 0.0.0.dev1__py3-none-any.whl → 0.0.0.dev3__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 +2 -3
- omlish/argparse.py +8 -8
- omlish/asyncs/__init__.py +2 -2
- omlish/asyncs/anyio.py +64 -1
- omlish/asyncs/asyncs.py +1 -3
- omlish/asyncs/futures.py +16 -15
- omlish/c3.py +5 -5
- omlish/check.py +8 -8
- omlish/collections/__init__.py +98 -63
- 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 +12 -12
- omlish/collections/cache/impl.py +27 -20
- omlish/collections/cache/types.py +1 -1
- omlish/collections/coerce.py +44 -44
- omlish/collections/frozen.py +9 -9
- omlish/collections/identity.py +4 -5
- omlish/collections/mappings.py +5 -5
- omlish/collections/ordered.py +8 -8
- omlish/collections/skiplist.py +7 -7
- omlish/collections/sorted.py +4 -4
- omlish/collections/treap.py +42 -17
- omlish/collections/treapmap.py +59 -7
- omlish/collections/unmodifiable.py +25 -24
- omlish/collections/utils.py +1 -1
- omlish/configs/flattening.py +8 -7
- omlish/configs/props.py +3 -3
- omlish/dataclasses/__init__.py +1 -1
- omlish/dataclasses/impl/__init__.py +18 -0
- omlish/dataclasses/impl/api.py +15 -24
- omlish/dataclasses/impl/as_.py +4 -4
- omlish/dataclasses/impl/exceptions.py +1 -1
- omlish/dataclasses/impl/fields.py +8 -8
- omlish/dataclasses/impl/frozen.py +2 -2
- omlish/dataclasses/impl/init.py +6 -6
- omlish/dataclasses/impl/internals.py +16 -1
- omlish/dataclasses/impl/main.py +4 -4
- omlish/dataclasses/impl/metaclass.py +2 -2
- omlish/dataclasses/impl/metadata.py +1 -1
- omlish/dataclasses/impl/order.py +2 -2
- omlish/dataclasses/impl/params.py +4 -38
- omlish/dataclasses/impl/reflect.py +1 -7
- omlish/dataclasses/impl/replace.py +1 -1
- omlish/dataclasses/impl/repr.py +24 -6
- omlish/dataclasses/impl/simple.py +2 -2
- omlish/dataclasses/impl/slots.py +2 -2
- omlish/dataclasses/impl/utils.py +7 -7
- omlish/defs.py +13 -17
- omlish/diag/procfs.py +334 -0
- omlish/diag/ps.py +47 -0
- omlish/{replserver → diag/replserver}/console.py +26 -28
- omlish/{replserver → diag/replserver}/server.py +12 -12
- omlish/dispatch/dispatch.py +14 -16
- omlish/dispatch/functions.py +1 -1
- omlish/dispatch/methods.py +6 -7
- omlish/docker.py +8 -6
- omlish/dynamic.py +13 -13
- omlish/fnpairs.py +311 -0
- omlish/graphs/dot/items.py +1 -1
- omlish/graphs/trees.py +25 -31
- omlish/inject/__init__.py +7 -7
- omlish/inject/elements.py +2 -2
- omlish/inject/exceptions.py +8 -8
- omlish/inject/impl/elements.py +4 -4
- omlish/inject/impl/injector.py +6 -6
- omlish/inject/impl/inspect.py +3 -3
- omlish/inject/impl/scopes.py +9 -9
- omlish/inject/injector.py +1 -1
- omlish/inject/providers.py +2 -2
- omlish/inject/proxy.py +5 -5
- omlish/iterators.py +62 -26
- omlish/json.py +7 -6
- omlish/lang/__init__.py +172 -112
- omlish/lang/cached.py +15 -10
- omlish/lang/classes/__init__.py +35 -24
- omlish/lang/classes/abstract.py +3 -3
- omlish/lang/classes/restrict.py +14 -14
- omlish/lang/classes/simple.py +2 -2
- omlish/lang/classes/virtual.py +5 -5
- omlish/lang/clsdct.py +2 -2
- omlish/lang/cmp.py +2 -2
- omlish/lang/contextmanagers.py +31 -25
- omlish/lang/datetimes.py +1 -1
- omlish/lang/descriptors.py +51 -6
- omlish/lang/exceptions.py +2 -0
- omlish/lang/functions.py +101 -35
- omlish/lang/imports.py +25 -30
- omlish/lang/iterables.py +2 -2
- omlish/lang/maybes.py +2 -1
- omlish/lang/objects.py +17 -11
- omlish/lang/resolving.py +1 -1
- omlish/lang/strings.py +1 -1
- omlish/lang/timeouts.py +53 -0
- omlish/lang/typing.py +5 -5
- omlish/libc.py +15 -11
- 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 +9 -9
- omlish/marshal/dataclasses.py +2 -2
- omlish/marshal/enums.py +2 -2
- omlish/marshal/exceptions.py +1 -1
- omlish/marshal/factories.py +10 -10
- omlish/marshal/global_.py +10 -4
- omlish/marshal/iterables.py +2 -2
- omlish/marshal/mappings.py +2 -2
- omlish/marshal/objects.py +1 -2
- omlish/marshal/optionals.py +4 -4
- omlish/marshal/polymorphism.py +4 -4
- omlish/marshal/registries.py +3 -3
- omlish/marshal/standard.py +6 -6
- omlish/marshal/utils.py +3 -3
- omlish/marshal/values.py +1 -1
- omlish/math.py +9 -9
- omlish/os.py +13 -4
- omlish/reflect.py +5 -15
- omlish/sql/__init__.py +0 -0
- omlish/sql/_abc.py +65 -0
- omlish/sql/dbs.py +90 -0
- omlish/stats.py +7 -8
- omlish/term.py +1 -1
- omlish/testing/pydevd.py +30 -12
- omlish/testing/pytest/inject/__init__.py +7 -0
- omlish/testing/pytest/inject/harness.py +24 -2
- omlish/testing/pytest/plugins/__init__.py +1 -1
- omlish/testing/pytest/plugins/pydevd.py +12 -0
- omlish/testing/pytest/plugins/switches.py +3 -3
- omlish/testing/testing.py +5 -5
- omlish/text/delimit.py +3 -6
- omlish/text/parts.py +3 -3
- omlish-0.0.0.dev3.dist-info/METADATA +31 -0
- omlish-0.0.0.dev3.dist-info/RECORD +191 -0
- {omlish-0.0.0.dev1.dist-info → omlish-0.0.0.dev3.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/testing/pytest/plugins/pycharm.py +0 -54
- omlish-0.0.0.dev1.dist-info/METADATA +0 -17
- omlish-0.0.0.dev1.dist-info/RECORD +0 -187
- /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-0.0.0.dev1.dist-info → omlish-0.0.0.dev3.dist-info}/LICENSE +0 -0
- {omlish-0.0.0.dev1.dist-info → omlish-0.0.0.dev3.dist-info}/top_level.txt +0 -0
omlish/dispatch/functions.py
CHANGED
omlish/dispatch/methods.py
CHANGED
|
@@ -4,6 +4,7 @@ TODO:
|
|
|
4
4
|
- ALT: A.f(super(), ... ? :/
|
|
5
5
|
- classmethod/staticmethod
|
|
6
6
|
"""
|
|
7
|
+
import contextlib
|
|
7
8
|
import functools
|
|
8
9
|
import typing as ta
|
|
9
10
|
import weakref
|
|
@@ -16,14 +17,14 @@ from .dispatch import get_impl_func_cls_set
|
|
|
16
17
|
T = ta.TypeVar('T')
|
|
17
18
|
|
|
18
19
|
|
|
19
|
-
def build_mro_dct(instance_cls: type, owner_cls:
|
|
20
|
+
def build_mro_dct(instance_cls: type, owner_cls: type | None = None) -> ta.Mapping[str, ta.Any]:
|
|
20
21
|
if owner_cls is None:
|
|
21
22
|
owner_cls = instance_cls
|
|
22
23
|
mro = instance_cls.__mro__[-2::-1]
|
|
23
24
|
try:
|
|
24
25
|
pos = mro.index(owner_cls)
|
|
25
26
|
except ValueError:
|
|
26
|
-
raise TypeError(f'Owner class {owner_cls} not in mro of instance class {instance_cls}')
|
|
27
|
+
raise TypeError(f'Owner class {owner_cls} not in mro of instance class {instance_cls}') from None
|
|
27
28
|
dct: dict[str, ta.Any] = {}
|
|
28
29
|
for cur_cls in mro[:pos + 1]:
|
|
29
30
|
dct.update(cur_cls.__dict__)
|
|
@@ -55,10 +56,8 @@ class Method:
|
|
|
55
56
|
def dispatch_func_cache_remove(k, self_ref=weakref.ref(self)):
|
|
56
57
|
if (ref_self := self_ref()) is not None:
|
|
57
58
|
cache = ref_self._dispatch_func_cache # noqa
|
|
58
|
-
|
|
59
|
+
with contextlib.suppress(KeyError):
|
|
59
60
|
del cache[k]
|
|
60
|
-
except KeyError:
|
|
61
|
-
pass
|
|
62
61
|
|
|
63
62
|
self._dispatch_func_cache_remove = dispatch_func_cache_remove
|
|
64
63
|
|
|
@@ -89,7 +88,7 @@ class Method:
|
|
|
89
88
|
|
|
90
89
|
return impl
|
|
91
90
|
|
|
92
|
-
def build_attr_dispatcher(self, instance_cls: type, owner_cls:
|
|
91
|
+
def build_attr_dispatcher(self, instance_cls: type, owner_cls: type | None = None) -> Dispatcher[str]:
|
|
93
92
|
disp: Dispatcher[str] = Dispatcher()
|
|
94
93
|
|
|
95
94
|
mro_dct = build_mro_dct(instance_cls, owner_cls)
|
|
@@ -158,5 +157,5 @@ class Method:
|
|
|
158
157
|
return func.__get__(instance)(*args, **kwargs) # noqa
|
|
159
158
|
|
|
160
159
|
|
|
161
|
-
def method(func):
|
|
160
|
+
def method(func): # noqa
|
|
162
161
|
return Method(func)
|
omlish/docker.py
CHANGED
|
@@ -118,28 +118,30 @@ class ComposeConfig:
|
|
|
118
118
|
self,
|
|
119
119
|
prefix: str,
|
|
120
120
|
*,
|
|
121
|
-
|
|
121
|
+
file_path: str | None = None,
|
|
122
122
|
) -> None:
|
|
123
123
|
super().__init__()
|
|
124
124
|
|
|
125
125
|
self._prefix = prefix
|
|
126
|
-
self.
|
|
126
|
+
self._file_path = file_path
|
|
127
127
|
|
|
128
128
|
@lang.cached_function
|
|
129
129
|
def get_config(self) -> ta.Mapping[str, ta.Any]:
|
|
130
|
-
with open(check.not_none(self.
|
|
130
|
+
with open(check.not_none(self._file_path)) as f:
|
|
131
131
|
buf = f.read()
|
|
132
|
-
|
|
132
|
+
return yaml.safe_load(buf)
|
|
133
133
|
|
|
134
|
+
@lang.cached_function
|
|
135
|
+
def get_services(self) -> ta.Mapping[str, ta.Any]:
|
|
134
136
|
ret = {}
|
|
135
|
-
for n, c in
|
|
137
|
+
for n, c in self.get_config()['services'].items():
|
|
136
138
|
check.state(n.startswith(self._prefix))
|
|
137
139
|
ret[n[len(self._prefix):]] = c
|
|
138
140
|
|
|
139
141
|
return ret
|
|
140
142
|
|
|
141
143
|
|
|
142
|
-
def timebomb_payload(delay_s:
|
|
144
|
+
def timebomb_payload(delay_s: float, name: str = 'omlish-docker-timebomb') -> str:
|
|
143
145
|
return (
|
|
144
146
|
'('
|
|
145
147
|
f'echo {shlex.quote(name)} && '
|
omlish/dynamic.py
CHANGED
|
@@ -25,7 +25,7 @@ _HOISTED_CODE_DEPTH: ta.MutableMapping[types.CodeType, int] = weakref.WeakKeyDic
|
|
|
25
25
|
_MAX_HOIST_DEPTH = 0
|
|
26
26
|
|
|
27
27
|
|
|
28
|
-
def hoist(depth=0):
|
|
28
|
+
def hoist(depth=0): # noqa
|
|
29
29
|
def inner(fn):
|
|
30
30
|
_HOISTED_CODE_DEPTH[fn.__code__] = depth
|
|
31
31
|
global _MAX_HOIST_DEPTH
|
|
@@ -49,10 +49,10 @@ class Var(ta.Generic[T]):
|
|
|
49
49
|
|
|
50
50
|
def __init__(
|
|
51
51
|
self,
|
|
52
|
-
default:
|
|
52
|
+
default: type[MISSING] | T = MISSING, # type: ignore
|
|
53
53
|
*,
|
|
54
|
-
new: ta.
|
|
55
|
-
validate: ta.
|
|
54
|
+
new: ta.Callable[[], T] | type[MISSING] = MISSING,
|
|
55
|
+
validate: ta.Callable[[T], None] | None = None,
|
|
56
56
|
) -> None:
|
|
57
57
|
super().__init__()
|
|
58
58
|
|
|
@@ -60,7 +60,7 @@ class Var(ta.Generic[T]):
|
|
|
60
60
|
raise TypeError('Cannot set both default and new')
|
|
61
61
|
elif default is not MISSING:
|
|
62
62
|
new = lambda: default # type: ignore
|
|
63
|
-
self._new:
|
|
63
|
+
self._new: type[MISSING] | ta.Callable[[], T] = new
|
|
64
64
|
self._validate = validate
|
|
65
65
|
self._bindings_by_frame: ta.MutableMapping[types.FrameType, ta.MutableMapping[int, Binding]] = weakref.WeakValueDictionary() # noqa
|
|
66
66
|
|
|
@@ -87,7 +87,7 @@ class Var(ta.Generic[T]):
|
|
|
87
87
|
self._validate(self.value)
|
|
88
88
|
return Binding(self, value, offset=offset)
|
|
89
89
|
|
|
90
|
-
def with_binding(self, value):
|
|
90
|
+
def with_binding(self, value): # noqa
|
|
91
91
|
def outer(fn):
|
|
92
92
|
@functools.wraps(fn)
|
|
93
93
|
def inner(*args, **kwargs):
|
|
@@ -96,7 +96,7 @@ class Var(ta.Generic[T]):
|
|
|
96
96
|
return inner
|
|
97
97
|
return outer
|
|
98
98
|
|
|
99
|
-
def with_binding_fn(self, binding_fn):
|
|
99
|
+
def with_binding_fn(self, binding_fn): # noqa
|
|
100
100
|
this = self
|
|
101
101
|
|
|
102
102
|
def outer(fn):
|
|
@@ -104,7 +104,7 @@ class Var(ta.Generic[T]):
|
|
|
104
104
|
|
|
105
105
|
@staticmethod
|
|
106
106
|
@functools.wraps(fn)
|
|
107
|
-
def __call__(*args, **kwargs):
|
|
107
|
+
def __call__(*args, **kwargs): # noqa
|
|
108
108
|
with this.binding(binding_fn(*args, **kwargs)):
|
|
109
109
|
return fn(*args, **kwargs)
|
|
110
110
|
|
|
@@ -119,7 +119,7 @@ class Var(ta.Generic[T]):
|
|
|
119
119
|
|
|
120
120
|
return inner
|
|
121
121
|
|
|
122
|
-
dct =
|
|
122
|
+
dct: dict[str, ta.Any] = {k: getattr(fn, k) for k in functools.WRAPPER_ASSIGNMENTS}
|
|
123
123
|
return lang.new_type(fn.__name__, (Descriptor,), dct)()
|
|
124
124
|
|
|
125
125
|
return outer
|
|
@@ -133,7 +133,7 @@ class Var(ta.Generic[T]):
|
|
|
133
133
|
except KeyError:
|
|
134
134
|
pass
|
|
135
135
|
else:
|
|
136
|
-
for level, frame_binding in sorted(frame_bindings.items()):
|
|
136
|
+
for level, frame_binding in sorted(frame_bindings.items()): # noqa
|
|
137
137
|
yield frame_binding._value # noqa
|
|
138
138
|
frame = frame.f_back
|
|
139
139
|
|
|
@@ -148,7 +148,7 @@ class Var(ta.Generic[T]):
|
|
|
148
148
|
try:
|
|
149
149
|
return next(self.values)
|
|
150
150
|
except StopIteration:
|
|
151
|
-
raise UnboundVarError
|
|
151
|
+
raise UnboundVarError from None
|
|
152
152
|
|
|
153
153
|
|
|
154
154
|
class Binding(ta.Generic[T]):
|
|
@@ -166,7 +166,7 @@ class Binding(ta.Generic[T]):
|
|
|
166
166
|
|
|
167
167
|
def __enter__(self) -> T:
|
|
168
168
|
frame = sys._getframe(self._offset).f_back # noqa
|
|
169
|
-
lag_frame:
|
|
169
|
+
lag_frame: types.FrameType | None = frame
|
|
170
170
|
while lag_frame is not None:
|
|
171
171
|
for cur_depth in range(_MAX_HOIST_DEPTH + 1):
|
|
172
172
|
if lag_frame is None:
|
|
@@ -213,7 +213,7 @@ class _GeneratorContextManager(contextlib._GeneratorContextManager): # noqa
|
|
|
213
213
|
return super().__enter__()
|
|
214
214
|
|
|
215
215
|
|
|
216
|
-
def contextmanager(fn):
|
|
216
|
+
def contextmanager(fn): # noqa
|
|
217
217
|
@functools.wraps(fn)
|
|
218
218
|
def helper(*args, **kwds):
|
|
219
219
|
return _GeneratorContextManager(fn, args, kwds)
|
omlish/fnpairs.py
ADDED
|
@@ -0,0 +1,311 @@
|
|
|
1
|
+
import abc
|
|
2
|
+
import codecs
|
|
3
|
+
import dataclasses as dc
|
|
4
|
+
import typing as ta
|
|
5
|
+
|
|
6
|
+
from . import lang
|
|
7
|
+
|
|
8
|
+
if ta.TYPE_CHECKING:
|
|
9
|
+
import bzip2 as _bzip2
|
|
10
|
+
import gzip as _gzip
|
|
11
|
+
import json as _json
|
|
12
|
+
import lzma as _lzma
|
|
13
|
+
import pickle as _pickle
|
|
14
|
+
import struct as _struct
|
|
15
|
+
import tomllib as _tomllib
|
|
16
|
+
|
|
17
|
+
else:
|
|
18
|
+
_bzip2 = lang.proxy_import('bzip2')
|
|
19
|
+
_gzip = lang.proxy_import('gzip')
|
|
20
|
+
_json = lang.proxy_import('json')
|
|
21
|
+
_lzma = lang.proxy_import('lzma')
|
|
22
|
+
_pickle = lang.proxy_import('pickle')
|
|
23
|
+
_struct = lang.proxy_import('struct')
|
|
24
|
+
_tomllib = lang.proxy_import('tomllib')
|
|
25
|
+
|
|
26
|
+
_zstd = lang.proxy_import('zstd')
|
|
27
|
+
_yaml = lang.proxy_import('yaml')
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
##
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
F = ta.TypeVar('F')
|
|
34
|
+
T = ta.TypeVar('T')
|
|
35
|
+
U = ta.TypeVar('U')
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class FnPair(ta.Generic[F, T], abc.ABC):
|
|
39
|
+
@abc.abstractmethod
|
|
40
|
+
def forward(self, f: F) -> T:
|
|
41
|
+
raise NotImplementedError
|
|
42
|
+
|
|
43
|
+
@abc.abstractmethod
|
|
44
|
+
def backward(self, t: T) -> F:
|
|
45
|
+
raise NotImplementedError
|
|
46
|
+
|
|
47
|
+
def invert(self) -> 'FnPair[T, F]':
|
|
48
|
+
if isinstance(self, Inverted):
|
|
49
|
+
return self.fp
|
|
50
|
+
return Inverted(self)
|
|
51
|
+
|
|
52
|
+
def compose(self, nxt: 'FnPair[T, U]') -> 'FnPair[F, U]':
|
|
53
|
+
return Composite((self, nxt))
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
##
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
@dc.dataclass(frozen=True)
|
|
60
|
+
class Simple(FnPair[F, T]):
|
|
61
|
+
forward: ta.Callable[[F], T] # type: ignore
|
|
62
|
+
backward: ta.Callable[[T], F] # type: ignore
|
|
63
|
+
|
|
64
|
+
def _forward(self, f: F) -> T:
|
|
65
|
+
return self.forward(f)
|
|
66
|
+
|
|
67
|
+
def _backward(self, t: T) -> F:
|
|
68
|
+
return self.backward(t)
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
# HACK: ABC workaround. Our dataclasses handle this with `override=True` but we don't want to dep that in here.
|
|
72
|
+
Simple.forward = Simple._forward # type: ignore # noqa
|
|
73
|
+
Simple.backward = Simple._backward # type: ignore # noqa
|
|
74
|
+
Simple.__abstractmethods__ = frozenset() # noqa
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
of = Simple
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
##
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
@dc.dataclass(frozen=True)
|
|
84
|
+
class Inverted(FnPair[F, T]):
|
|
85
|
+
fp: FnPair[T, F]
|
|
86
|
+
|
|
87
|
+
def forward(self, f: F) -> T:
|
|
88
|
+
return self.fp.backward(f)
|
|
89
|
+
|
|
90
|
+
def backward(self, t: T) -> F:
|
|
91
|
+
return self.fp.forward(t)
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
##
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
@dc.dataclass(frozen=True)
|
|
98
|
+
class Composite(FnPair[F, T]):
|
|
99
|
+
children: ta.Sequence[FnPair]
|
|
100
|
+
|
|
101
|
+
def forward(self, f: F) -> T:
|
|
102
|
+
for c in self.children:
|
|
103
|
+
f = c.forward(f)
|
|
104
|
+
return ta.cast(T, f)
|
|
105
|
+
|
|
106
|
+
def backward(self, t: T) -> F:
|
|
107
|
+
for c in reversed(self.children):
|
|
108
|
+
t = c.backward(t)
|
|
109
|
+
return ta.cast(F, t)
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
##
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
@dc.dataclass(frozen=True)
|
|
116
|
+
class Text(FnPair[str, bytes]):
|
|
117
|
+
ci: codecs.CodecInfo
|
|
118
|
+
encode_errors: str = dc.field(default='strict', kw_only=True)
|
|
119
|
+
decode_errors: str = dc.field(default='strict', kw_only=True)
|
|
120
|
+
|
|
121
|
+
def forward(self, f: str) -> bytes:
|
|
122
|
+
# Python ignores the returned length:
|
|
123
|
+
# https://github.com/python/cpython/blob/7431c3799efbd06ed03ee70b64420f45e83b3667/Python/codecs.c#L424
|
|
124
|
+
t, _ = self.ci.encode(f, self.encode_errors)
|
|
125
|
+
return t
|
|
126
|
+
|
|
127
|
+
def backward(self, t: bytes) -> str:
|
|
128
|
+
f, _ = self.ci.decode(t, self.decode_errors)
|
|
129
|
+
return f
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def text(name: str, *, encode_errors: str = 'strict', decode_errors: str = 'strict') -> Text:
|
|
133
|
+
ci = codecs.lookup(name)
|
|
134
|
+
if not ci._is_text_encoding: # noqa
|
|
135
|
+
raise TypeError(f'must be text codec: {name}')
|
|
136
|
+
return Text(ci, encode_errors=encode_errors, decode_errors=decode_errors)
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
UTF8 = text('utf-8')
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
#
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
@dc.dataclass(frozen=True)
|
|
146
|
+
class Optional(FnPair[ta.Optional[F], ta.Optional[T]]):
|
|
147
|
+
fp: FnPair[F, T]
|
|
148
|
+
|
|
149
|
+
def forward(self, f: ta.Optional[F]) -> ta.Optional[T]:
|
|
150
|
+
return None if f is None else self.fp.forward(f)
|
|
151
|
+
|
|
152
|
+
def backward(self, t: ta.Optional[T]) -> ta.Optional[F]:
|
|
153
|
+
return None if t is None else self.fp.backward(t)
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
class Lines(FnPair[ta.Sequence[str], str]):
|
|
157
|
+
def forward(self, f: ta.Sequence[str]) -> str:
|
|
158
|
+
return '\n'.join(f)
|
|
159
|
+
|
|
160
|
+
def backward(self, t: str) -> ta.Sequence[str]:
|
|
161
|
+
return t.splitlines()
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
##
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
_EXTENSION_REGISTRY: dict[str, type[FnPair]] = {}
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
def _register_extension(*ss):
|
|
171
|
+
def inner(cls):
|
|
172
|
+
for s in ss:
|
|
173
|
+
if s in _EXTENSION_REGISTRY:
|
|
174
|
+
raise Exception(s)
|
|
175
|
+
_EXTENSION_REGISTRY[s] = cls
|
|
176
|
+
return cls
|
|
177
|
+
return inner
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
##
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
class Compression(FnPair[bytes, bytes], abc.ABC):
|
|
184
|
+
pass
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
@_register_extension('gz')
|
|
188
|
+
@dc.dataclass(frozen=True)
|
|
189
|
+
class Gzip(Compression):
|
|
190
|
+
compresslevel: int = 9
|
|
191
|
+
|
|
192
|
+
def forward(self, f: bytes) -> bytes:
|
|
193
|
+
return _gzip.compress(f, compresslevel=self.compresslevel)
|
|
194
|
+
|
|
195
|
+
def backward(self, t: bytes) -> bytes:
|
|
196
|
+
return _gzip.decompress(t)
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
@_register_extension('bz2')
|
|
200
|
+
@dc.dataclass(frozen=True)
|
|
201
|
+
class Bzip2(Compression):
|
|
202
|
+
compresslevel: int = 9
|
|
203
|
+
|
|
204
|
+
def forward(self, f: bytes) -> bytes:
|
|
205
|
+
return _bzip2.compress(f, compresslevel=self.compresslevel)
|
|
206
|
+
|
|
207
|
+
def backward(self, t: bytes) -> bytes:
|
|
208
|
+
return _bzip2.decompress(t)
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
@_register_extension('lzma')
|
|
212
|
+
class Lzma(Compression):
|
|
213
|
+
def forward(self, f: bytes) -> bytes:
|
|
214
|
+
return _lzma.compress(f)
|
|
215
|
+
|
|
216
|
+
def backward(self, t: bytes) -> bytes:
|
|
217
|
+
return _lzma.decompress(t)
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
#
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
@_register_extension('zstd')
|
|
224
|
+
class Zstd(Compression):
|
|
225
|
+
def forward(self, f: bytes) -> bytes:
|
|
226
|
+
return _zstd.compress(f)
|
|
227
|
+
|
|
228
|
+
def backward(self, t: bytes) -> bytes:
|
|
229
|
+
return _zstd.decompress(t)
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
##
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
@dc.dataclass(frozen=True)
|
|
236
|
+
class Struct(FnPair[tuple, bytes]):
|
|
237
|
+
fmt: str
|
|
238
|
+
|
|
239
|
+
def forward(self, f: tuple) -> bytes:
|
|
240
|
+
return _struct.pack(self.fmt, *f)
|
|
241
|
+
|
|
242
|
+
def backward(self, t: bytes) -> tuple:
|
|
243
|
+
return _struct.unpack(self.fmt, t)
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
@_register_extension('pkl')
|
|
247
|
+
@dc.dataclass(frozen=True)
|
|
248
|
+
class Pickle(FnPair[ta.Any, bytes]):
|
|
249
|
+
protocol: int | None = None
|
|
250
|
+
|
|
251
|
+
def forward(self, f: ta.Any) -> bytes:
|
|
252
|
+
return _pickle.dumps(f, protocol=self.protocol)
|
|
253
|
+
|
|
254
|
+
def backward(self, t: bytes) -> ta.Any:
|
|
255
|
+
return _pickle.loads(t)
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
@_register_extension('json')
|
|
259
|
+
@dc.dataclass(frozen=True)
|
|
260
|
+
class Json(FnPair[ta.Any, str]):
|
|
261
|
+
indent: int | str | None = dc.field(default=None, kw_only=True)
|
|
262
|
+
separators: tuple[str, str] | None = dc.field(default=None, kw_only=True)
|
|
263
|
+
|
|
264
|
+
def forward(self, f: ta.Any) -> str:
|
|
265
|
+
return _json.dumps(f, indent=self.indent, separators=self.separators)
|
|
266
|
+
|
|
267
|
+
def backward(self, t: str) -> ta.Any:
|
|
268
|
+
return _json.loads(t)
|
|
269
|
+
|
|
270
|
+
|
|
271
|
+
JSON = Json()
|
|
272
|
+
PRETTY_JSON = Json(indent=2)
|
|
273
|
+
COMPACT_JSON = Json(separators=(',', ':'))
|
|
274
|
+
|
|
275
|
+
|
|
276
|
+
@_register_extension('jsonl')
|
|
277
|
+
class JsonLines(FnPair[ta.Sequence[ta.Any], str]):
|
|
278
|
+
def forward(self, f: ta.Sequence[ta.Any]) -> str:
|
|
279
|
+
return '\n'.join(_json.dumps(e) for e in f)
|
|
280
|
+
|
|
281
|
+
def backward(self, t: str) -> ta.Sequence[ta.Any]:
|
|
282
|
+
return [_json.loads(l) for l in t.splitlines()]
|
|
283
|
+
|
|
284
|
+
|
|
285
|
+
@_register_extension('toml')
|
|
286
|
+
class Toml(FnPair[ta.Any, str]):
|
|
287
|
+
def forward(self, f: ta.Any) -> str:
|
|
288
|
+
raise NotImplementedError
|
|
289
|
+
|
|
290
|
+
def backward(self, t: str) -> ta.Any:
|
|
291
|
+
return _tomllib.loads(t)
|
|
292
|
+
|
|
293
|
+
|
|
294
|
+
#
|
|
295
|
+
|
|
296
|
+
|
|
297
|
+
@_register_extension('yml', 'yaml')
|
|
298
|
+
class Yaml(FnPair[ta.Any, str]):
|
|
299
|
+
def forward(self, f: ta.Any) -> str:
|
|
300
|
+
return _yaml.dump(f)
|
|
301
|
+
|
|
302
|
+
def backward(self, t: str) -> ta.Any:
|
|
303
|
+
return _yaml.safe_load(t)
|
|
304
|
+
|
|
305
|
+
|
|
306
|
+
class UnsafeYaml(FnPair[ta.Any, str]):
|
|
307
|
+
def forward(self, f: ta.Any) -> str:
|
|
308
|
+
return _yaml.dump(f)
|
|
309
|
+
|
|
310
|
+
def backward(self, t: str) -> ta.Any:
|
|
311
|
+
return _yaml.safe_load(t, loader=_yaml.FullLoader)
|
omlish/graphs/dot/items.py
CHANGED
omlish/graphs/trees.py
CHANGED
|
@@ -18,7 +18,7 @@ NodeWalker = ta.Callable[[NodeT], ta.Iterable[NodeT]]
|
|
|
18
18
|
NodeGenerator = ta.Generator[NodeT, None, None]
|
|
19
19
|
|
|
20
20
|
|
|
21
|
-
class
|
|
21
|
+
class NodeError(ta.Generic[NodeT], Exception):
|
|
22
22
|
def __init__(self, node: NodeT, msg: str, *args, **kwargs) -> None:
|
|
23
23
|
super().__init__(msg, *args, **kwargs) # noqa
|
|
24
24
|
self._node = node
|
|
@@ -28,12 +28,12 @@ class NodeException(ta.Generic[NodeT], Exception):
|
|
|
28
28
|
return self._node
|
|
29
29
|
|
|
30
30
|
|
|
31
|
-
class
|
|
31
|
+
class DuplicateNodeError(NodeError[NodeT]):
|
|
32
32
|
def __init__(self, node: NodeT, *args, **kwargs) -> None:
|
|
33
33
|
super().__init__(node, f'Duplicate node: {node!r}', *args, **kwargs)
|
|
34
34
|
|
|
35
35
|
|
|
36
|
-
class
|
|
36
|
+
class UnknownNodeError(NodeError[NodeT]):
|
|
37
37
|
def __init__(self, node: NodeT, *args, **kwargs) -> None:
|
|
38
38
|
super().__init__(node, f'Unknown node: {node!r}', *args, **kwargs)
|
|
39
39
|
|
|
@@ -55,19 +55,19 @@ class BasicTreeAnalysis(ta.Generic[NodeT]):
|
|
|
55
55
|
|
|
56
56
|
self._set_fac: ta.Callable[..., ta.MutableSet[NodeT]] = col.IdentitySet if identity else set
|
|
57
57
|
self._dict_fac: ta.Callable[..., ta.MutableMapping[NodeT, ta.Any]] = col.IdentityKeyDict if identity else dict
|
|
58
|
-
self._idx_seq_fac: ta.Callable[..., col.IndexedSeq[NodeT]] = functools.partial(col.IndexedSeq, identity=identity) # noqa
|
|
58
|
+
self._idx_seq_fac: ta.Callable[..., col.IndexedSeq[NodeT]] = functools.partial(col.IndexedSeq, identity=identity) # type: ignore # noqa
|
|
59
59
|
|
|
60
|
-
def walk(cur: NodeT, parent:
|
|
60
|
+
def walk(cur: NodeT, parent: NodeT | None) -> None:
|
|
61
61
|
check.not_none(cur)
|
|
62
62
|
if cur in node_set:
|
|
63
|
-
raise
|
|
63
|
+
raise DuplicateNodeError(cur)
|
|
64
64
|
|
|
65
65
|
nodes.append(cur)
|
|
66
66
|
node_set.add(cur)
|
|
67
67
|
if parent is None:
|
|
68
68
|
check.state(cur is root)
|
|
69
69
|
elif parent not in node_set:
|
|
70
|
-
raise
|
|
70
|
+
raise UnknownNodeError(parent)
|
|
71
71
|
|
|
72
72
|
parents_by_node[cur] = parent
|
|
73
73
|
|
|
@@ -77,22 +77,22 @@ class BasicTreeAnalysis(ta.Generic[NodeT]):
|
|
|
77
77
|
walk(child, cur)
|
|
78
78
|
|
|
79
79
|
nodes: list[NodeT] = []
|
|
80
|
-
node_set: ta.MutableSet[NodeT] = self._set_fac()
|
|
81
|
-
children_by_node: ta.MutableMapping[
|
|
82
|
-
child_sets_by_node: ta.MutableMapping[ta.Optional[NodeT], ta.AbstractSet[NodeT]] = self._dict_fac()
|
|
83
|
-
parents_by_node: ta.MutableMapping[NodeT,
|
|
80
|
+
node_set: ta.MutableSet[NodeT] = self._set_fac()
|
|
81
|
+
children_by_node: ta.MutableMapping[NodeT | None, ta.Sequence[NodeT]] = self._dict_fac()
|
|
82
|
+
child_sets_by_node: ta.MutableMapping[ta.Optional[NodeT], ta.AbstractSet[NodeT]] = self._dict_fac()
|
|
83
|
+
parents_by_node: ta.MutableMapping[NodeT, NodeT | None] = self._dict_fac()
|
|
84
84
|
|
|
85
85
|
children_by_node[None] = [root]
|
|
86
|
-
child_sets_by_node[None] = self._set_fac([root])
|
|
86
|
+
child_sets_by_node[None] = self._set_fac([root])
|
|
87
87
|
|
|
88
88
|
walk(root, None)
|
|
89
89
|
|
|
90
|
-
self._nodes = self._idx_seq_fac(nodes)
|
|
90
|
+
self._nodes = self._idx_seq_fac(nodes)
|
|
91
91
|
self._node_set: ta.AbstractSet[NodeT] = node_set
|
|
92
|
-
self._children_by_node: ta.Mapping[
|
|
92
|
+
self._children_by_node: ta.Mapping[NodeT | None, col.IndexedSeq[NodeT]] = self._dict_fac(
|
|
93
93
|
[(n, self._idx_seq_fac(cs)) for n, cs in children_by_node.items()])
|
|
94
|
-
self._child_sets_by_node: ta.Mapping[
|
|
95
|
-
self._parents_by_node: ta.Mapping[NodeT,
|
|
94
|
+
self._child_sets_by_node: ta.Mapping[NodeT | None, ta.AbstractSet[NodeT]] = child_sets_by_node
|
|
95
|
+
self._parents_by_node: ta.Mapping[NodeT, NodeT | None] = parents_by_node
|
|
96
96
|
|
|
97
97
|
@property
|
|
98
98
|
def root(self) -> NodeT:
|
|
@@ -115,27 +115,24 @@ class BasicTreeAnalysis(ta.Generic[NodeT]):
|
|
|
115
115
|
return self._node_set
|
|
116
116
|
|
|
117
117
|
@property
|
|
118
|
-
def children_by_node(self) -> ta.Mapping[
|
|
118
|
+
def children_by_node(self) -> ta.Mapping[NodeT | None, col.IndexedSeq[NodeT]]:
|
|
119
119
|
return self._children_by_node
|
|
120
120
|
|
|
121
121
|
@property
|
|
122
|
-
def child_sets_by_node(self) -> ta.Mapping[
|
|
122
|
+
def child_sets_by_node(self) -> ta.Mapping[NodeT | None, ta.AbstractSet[NodeT]]:
|
|
123
123
|
return self._child_sets_by_node
|
|
124
124
|
|
|
125
125
|
@property
|
|
126
|
-
def parents_by_node(self) -> ta.Mapping[NodeT,
|
|
126
|
+
def parents_by_node(self) -> ta.Mapping[NodeT, NodeT | None]:
|
|
127
127
|
return self._parents_by_node
|
|
128
128
|
|
|
129
129
|
@classmethod
|
|
130
130
|
def from_parents(
|
|
131
131
|
cls,
|
|
132
|
-
src: ta.
|
|
133
|
-
ta.Mapping[NodeT, ta.Optional[NodeT]],
|
|
134
|
-
ta.Iterable[tuple[NodeT, ta.Optional[NodeT]]],
|
|
135
|
-
],
|
|
132
|
+
src: ta.Mapping[NodeT, NodeT | None] | ta.Iterable[tuple[NodeT, NodeT | None]],
|
|
136
133
|
*,
|
|
137
134
|
identity: bool = False,
|
|
138
|
-
**kwargs
|
|
135
|
+
**kwargs,
|
|
139
136
|
) -> 'BasicTreeAnalysis[NodeT]':
|
|
140
137
|
pairs: ta.Sequence[tuple[NodeT, NodeT]]
|
|
141
138
|
if isinstance(src, ta.Mapping):
|
|
@@ -166,13 +163,10 @@ class BasicTreeAnalysis(ta.Generic[NodeT]):
|
|
|
166
163
|
@classmethod
|
|
167
164
|
def from_children(
|
|
168
165
|
cls,
|
|
169
|
-
src: ta.
|
|
170
|
-
ta.Mapping[NodeT, ta.Iterable[NodeT]],
|
|
171
|
-
ta.Iterable[tuple[NodeT, ta.Iterable[NodeT]]],
|
|
172
|
-
],
|
|
166
|
+
src: ta.Mapping[NodeT, ta.Iterable[NodeT]] | ta.Iterable[tuple[NodeT, ta.Iterable[NodeT]]],
|
|
173
167
|
*,
|
|
174
168
|
identity: bool = False,
|
|
175
|
-
**kwargs
|
|
169
|
+
**kwargs,
|
|
176
170
|
) -> 'BasicTreeAnalysis[NodeT]':
|
|
177
171
|
pairs: ta.Sequence[tuple[NodeT, ta.Sequence[NodeT]]]
|
|
178
172
|
if isinstance(src, ta.Mapping):
|
|
@@ -222,7 +216,7 @@ class BasicTreeAnalysis(ta.Generic[NodeT]):
|
|
|
222
216
|
return ret # type: ignore
|
|
223
217
|
|
|
224
218
|
def iter_ancestors(self, node: NodeT) -> NodeGenerator[NodeT]:
|
|
225
|
-
cur:
|
|
219
|
+
cur: NodeT | None = node
|
|
226
220
|
while True:
|
|
227
221
|
cur = self.parents_by_node.get(cur) # type: ignore
|
|
228
222
|
if cur is None:
|
|
@@ -232,7 +226,7 @@ class BasicTreeAnalysis(ta.Generic[NodeT]):
|
|
|
232
226
|
def get_lineage(self, node: NodeT) -> col.IndexedSeq[NodeT]:
|
|
233
227
|
return self._idx_seq_fac(reversed([node, *self.iter_ancestors(node)]))
|
|
234
228
|
|
|
235
|
-
def get_first_parent_of_type(self, node: NodeT, ty: type[T]) ->
|
|
229
|
+
def get_first_parent_of_type(self, node: NodeT, ty: type[T]) -> T | None:
|
|
236
230
|
for cur in self.iter_ancestors(node):
|
|
237
231
|
if isinstance(cur, ty):
|
|
238
232
|
return cur
|
omlish/inject/__init__.py
CHANGED
|
@@ -18,13 +18,13 @@ from .elements import ( # noqa
|
|
|
18
18
|
)
|
|
19
19
|
|
|
20
20
|
from .exceptions import ( # noqa
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
21
|
+
BaseKeyError,
|
|
22
|
+
CyclicDependencyError,
|
|
23
|
+
DuplicateKeyError,
|
|
24
|
+
ScopeAlreadyOpenError,
|
|
25
|
+
ScopeError,
|
|
26
|
+
ScopeNotOpenError,
|
|
27
|
+
UnboundKeyError,
|
|
28
28
|
)
|
|
29
29
|
|
|
30
30
|
from .injector import ( # noqa
|