omlish 0.0.0.dev2__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 +1 -2
- omlish/argparse.py +4 -4
- omlish/asyncs/__init__.py +2 -2
- omlish/asyncs/anyio.py +13 -11
- omlish/asyncs/asyncs.py +1 -3
- omlish/asyncs/futures.py +10 -9
- 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 +8 -8
- omlish/fnpairs.py +311 -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 +4 -4
- omlish/inject/impl/injector.py +5 -5
- omlish/inject/impl/inspect.py +2 -2
- omlish/inject/impl/scopes.py +9 -9
- omlish/inject/proxy.py +5 -5
- omlish/iterators.py +19 -24
- omlish/json.py +7 -6
- omlish/lang/__init__.py +9 -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/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/stats.py +4 -5
- omlish/term.py +1 -1
- omlish/testing/pydevd.py +26 -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.dev3.dist-info}/METADATA +1 -1
- omlish-0.0.0.dev3.dist-info/RECORD +191 -0
- {omlish-0.0.0.dev2.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-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.dev3.dist-info}/LICENSE +0 -0
- {omlish-0.0.0.dev2.dist-info → omlish-0.0.0.dev3.dist-info}/top_level.txt +0 -0
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/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
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,19 +77,19 @@ 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[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()
|
|
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[NodeT | None, col.IndexedSeq[NodeT]] = self._dict_fac(
|
|
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
94
|
self._child_sets_by_node: ta.Mapping[NodeT | None, ta.AbstractSet[NodeT]] = child_sets_by_node
|
|
95
95
|
self._parents_by_node: ta.Mapping[NodeT, NodeT | None] = parents_by_node
|
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
|
omlish/inject/elements.py
CHANGED
omlish/inject/exceptions.py
CHANGED
|
@@ -9,7 +9,7 @@ from .types import Scope
|
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
@dc.dataclass()
|
|
12
|
-
class
|
|
12
|
+
class BaseKeyError(Exception):
|
|
13
13
|
key: Key
|
|
14
14
|
|
|
15
15
|
source: ta.Any = None
|
|
@@ -17,17 +17,17 @@ class KeyException(Exception):
|
|
|
17
17
|
|
|
18
18
|
|
|
19
19
|
@dc.dataclass()
|
|
20
|
-
class
|
|
20
|
+
class UnboundKeyError(KeyError):
|
|
21
21
|
pass
|
|
22
22
|
|
|
23
23
|
|
|
24
24
|
@dc.dataclass()
|
|
25
|
-
class
|
|
25
|
+
class DuplicateKeyError(KeyError):
|
|
26
26
|
pass
|
|
27
27
|
|
|
28
28
|
|
|
29
29
|
@dc.dataclass()
|
|
30
|
-
class
|
|
30
|
+
class CyclicDependencyError(KeyError):
|
|
31
31
|
pass
|
|
32
32
|
|
|
33
33
|
|
|
@@ -35,15 +35,15 @@ class CyclicDependencyException(KeyException):
|
|
|
35
35
|
|
|
36
36
|
|
|
37
37
|
@dc.dataclass()
|
|
38
|
-
class
|
|
38
|
+
class ScopeError(Exception):
|
|
39
39
|
scope: Scope
|
|
40
40
|
|
|
41
41
|
|
|
42
42
|
@dc.dataclass()
|
|
43
|
-
class
|
|
43
|
+
class ScopeAlreadyOpenError(ScopeError):
|
|
44
44
|
pass
|
|
45
45
|
|
|
46
46
|
|
|
47
47
|
@dc.dataclass()
|
|
48
|
-
class
|
|
48
|
+
class ScopeNotOpenError(ScopeError):
|
|
49
49
|
pass
|
omlish/inject/impl/elements.py
CHANGED
|
@@ -25,7 +25,7 @@ from ..bindings import Binding
|
|
|
25
25
|
from ..eagers import Eager
|
|
26
26
|
from ..elements import Element
|
|
27
27
|
from ..elements import Elements
|
|
28
|
-
from ..exceptions import
|
|
28
|
+
from ..exceptions import DuplicateKeyError
|
|
29
29
|
from ..keys import Key
|
|
30
30
|
from ..overrides import Overrides
|
|
31
31
|
from ..private import Expose
|
|
@@ -51,7 +51,7 @@ class ElementCollection(lang.Final):
|
|
|
51
51
|
|
|
52
52
|
self._es = check.isinstance(es, Elements)
|
|
53
53
|
|
|
54
|
-
self._private_infos: ta.MutableMapping[Private,
|
|
54
|
+
self._private_infos: ta.MutableMapping[Private, private_.PrivateInfo] | None = None
|
|
55
55
|
|
|
56
56
|
##
|
|
57
57
|
|
|
@@ -98,7 +98,7 @@ class ElementCollection(lang.Final):
|
|
|
98
98
|
try:
|
|
99
99
|
bs = ovr[k]
|
|
100
100
|
except KeyError:
|
|
101
|
-
bs =
|
|
101
|
+
bs = b
|
|
102
102
|
add(k, *bs)
|
|
103
103
|
|
|
104
104
|
else:
|
|
@@ -139,7 +139,7 @@ class ElementCollection(lang.Final):
|
|
|
139
139
|
mm.setdefault(k, []).extend(bis)
|
|
140
140
|
else:
|
|
141
141
|
if len(bis) > 1:
|
|
142
|
-
raise
|
|
142
|
+
raise DuplicateKeyError(k)
|
|
143
143
|
[pm[k]] = bis
|
|
144
144
|
|
|
145
145
|
if mm:
|
omlish/inject/impl/injector.py
CHANGED
|
@@ -16,8 +16,8 @@ from ... import check
|
|
|
16
16
|
from ... import lang
|
|
17
17
|
from ..eagers import Eager
|
|
18
18
|
from ..elements import Elements
|
|
19
|
-
from ..exceptions import
|
|
20
|
-
from ..exceptions import
|
|
19
|
+
from ..exceptions import CyclicDependencyError
|
|
20
|
+
from ..exceptions import UnboundKeyError
|
|
21
21
|
from ..injector import Injector
|
|
22
22
|
from ..inspect import KwargsTarget
|
|
23
23
|
from ..keys import Key
|
|
@@ -54,7 +54,7 @@ class InjectorImpl(Injector, lang.Final):
|
|
|
54
54
|
self._bim = ec.binding_impl_map()
|
|
55
55
|
|
|
56
56
|
self._cs: weakref.WeakSet[InjectorImpl] | None = None
|
|
57
|
-
self._root: InjectorImpl = p._root if p is not None else self
|
|
57
|
+
self._root: InjectorImpl = p._root if p is not None else self # noqa
|
|
58
58
|
|
|
59
59
|
self.__cur_req: InjectorImpl._Request | None = None
|
|
60
60
|
|
|
@@ -97,7 +97,7 @@ class InjectorImpl(Injector, lang.Final):
|
|
|
97
97
|
except KeyError:
|
|
98
98
|
pass
|
|
99
99
|
if key in self._seen_keys:
|
|
100
|
-
raise
|
|
100
|
+
raise CyclicDependencyError(key)
|
|
101
101
|
self._seen_keys.add(key)
|
|
102
102
|
return lang.empty()
|
|
103
103
|
|
|
@@ -154,7 +154,7 @@ class InjectorImpl(Injector, lang.Final):
|
|
|
154
154
|
v = self.try_provide(key)
|
|
155
155
|
if v.present:
|
|
156
156
|
return v.must()
|
|
157
|
-
raise
|
|
157
|
+
raise UnboundKeyError(key)
|
|
158
158
|
|
|
159
159
|
def provide_kwargs(self, kt: KwargsTarget) -> ta.Mapping[str, ta.Any]:
|
|
160
160
|
ret: dict[str, ta.Any] = {}
|
omlish/inject/impl/inspect.py
CHANGED
|
@@ -11,7 +11,7 @@ import typing as ta
|
|
|
11
11
|
import weakref
|
|
12
12
|
|
|
13
13
|
from ... import reflect as rfl
|
|
14
|
-
from ..exceptions import
|
|
14
|
+
from ..exceptions import DuplicateKeyError
|
|
15
15
|
from ..inspect import Kwarg
|
|
16
16
|
from ..inspect import KwargsTarget
|
|
17
17
|
from ..keys import Key
|
|
@@ -83,7 +83,7 @@ def build_kwargs_target(
|
|
|
83
83
|
k = tag(k, pt)
|
|
84
84
|
|
|
85
85
|
if k in seen:
|
|
86
|
-
raise
|
|
86
|
+
raise DuplicateKeyError(k)
|
|
87
87
|
seen.add(k)
|
|
88
88
|
|
|
89
89
|
kws.append(Kwarg(
|
omlish/inject/impl/scopes.py
CHANGED
|
@@ -9,8 +9,8 @@ from ... import lang
|
|
|
9
9
|
from ..bindings import Binding
|
|
10
10
|
from ..elements import Elements
|
|
11
11
|
from ..elements import as_elements
|
|
12
|
-
from ..exceptions import
|
|
13
|
-
from ..exceptions import
|
|
12
|
+
from ..exceptions import ScopeAlreadyOpenError
|
|
13
|
+
from ..exceptions import ScopeNotOpenError
|
|
14
14
|
from ..injector import Injector
|
|
15
15
|
from ..keys import Key
|
|
16
16
|
from ..providers import Provider
|
|
@@ -134,7 +134,7 @@ class SeededScopeImpl(ScopeImpl):
|
|
|
134
134
|
|
|
135
135
|
def must_state(self) -> 'SeededScopeImpl.State':
|
|
136
136
|
if (st := self._st) is None:
|
|
137
|
-
raise
|
|
137
|
+
raise ScopeNotOpenError(self._ss)
|
|
138
138
|
return st
|
|
139
139
|
|
|
140
140
|
class Manager(SeededScope.Manager, lang.Final):
|
|
@@ -147,14 +147,14 @@ class SeededScopeImpl(ScopeImpl):
|
|
|
147
147
|
@contextlib.contextmanager
|
|
148
148
|
def __call__(self, seeds: ta.Mapping[Key, ta.Any]) -> ta.Generator[None, None, None]:
|
|
149
149
|
try:
|
|
150
|
-
if self._ssi._st is not None:
|
|
151
|
-
raise
|
|
152
|
-
self._ssi._st = SeededScopeImpl.State(dict(seeds))
|
|
150
|
+
if self._ssi._st is not None: # noqa
|
|
151
|
+
raise ScopeAlreadyOpenError(self._ss)
|
|
152
|
+
self._ssi._st = SeededScopeImpl.State(dict(seeds)) # noqa
|
|
153
153
|
yield
|
|
154
154
|
finally:
|
|
155
|
-
if self._ssi._st is None:
|
|
156
|
-
raise
|
|
157
|
-
self._ssi._st = None
|
|
155
|
+
if self._ssi._st is None: # noqa
|
|
156
|
+
raise ScopeNotOpenError(self._ss)
|
|
157
|
+
self._ssi._st = None # noqa
|
|
158
158
|
|
|
159
159
|
def auto_elements(self) -> Elements:
|
|
160
160
|
return as_elements(
|
omlish/inject/proxy.py
CHANGED
|
@@ -22,7 +22,7 @@ def _cyclic_dependency_proxy() -> tuple[type, ta.Callable[[ta.Any, ta.Any], None
|
|
|
22
22
|
def __init__(self, cls):
|
|
23
23
|
super().__init__(_CyclicDependencyPlaceholder(cls))
|
|
24
24
|
if isinstance(cls, type):
|
|
25
|
-
self._self__class__ = cls
|
|
25
|
+
self._self__class__ = cls # noqa
|
|
26
26
|
|
|
27
27
|
def __repr__(self) -> str:
|
|
28
28
|
return f'_CyclicDependencyProxy({self.__wrapped__!r})'
|
|
@@ -35,14 +35,14 @@ def _cyclic_dependency_proxy() -> tuple[type, ta.Callable[[ta.Any, ta.Any], None
|
|
|
35
35
|
pass
|
|
36
36
|
return object.__getattribute__(self, att) # noqa
|
|
37
37
|
|
|
38
|
-
def
|
|
38
|
+
def set_obj(prox, obj):
|
|
39
39
|
check.state(type(prox) is _CyclicDependencyProxy)
|
|
40
40
|
check.not_isinstance(obj, _CyclicDependencyPlaceholder)
|
|
41
41
|
check.isinstance(prox.__wrapped__, _CyclicDependencyPlaceholder)
|
|
42
42
|
if hasattr(prox, '_self__class__'):
|
|
43
|
-
check.issubclass(type(obj), prox._self__class__)
|
|
43
|
+
check.issubclass(type(obj), prox._self__class__) # noqa
|
|
44
44
|
prox.__wrapped__ = obj
|
|
45
45
|
if hasattr(prox, '_self__class__'):
|
|
46
|
-
del prox._self__class__
|
|
46
|
+
del prox._self__class__ # noqa
|
|
47
47
|
|
|
48
|
-
return (_CyclicDependencyProxy,
|
|
48
|
+
return (_CyclicDependencyProxy, set_obj) # noqa
|