omlish 0.0.0.dev119__py3-none-any.whl → 0.0.0.dev121__py3-none-any.whl
Sign up to get free protection for your applications and to get access to all the features.
- omlish/__about__.py +2 -2
- omlish/inject/binder.py +1 -1
- omlish/inject/impl/inspect.py +9 -11
- omlish/lite/cached.py +1 -1
- omlish/lite/contextmanagers.py +4 -0
- omlish/lite/inject.py +624 -0
- omlish/lite/maybes.py +45 -0
- omlish/specs/jmespath/__init__.py +5 -1
- omlish/specs/jmespath/ast.py +29 -3
- omlish/specs/jmespath/functions.py +8 -0
- omlish/specs/jmespath/parser.py +6 -3
- omlish/specs/jmespath/visitor.py +12 -9
- {omlish-0.0.0.dev119.dist-info → omlish-0.0.0.dev121.dist-info}/METADATA +1 -1
- {omlish-0.0.0.dev119.dist-info → omlish-0.0.0.dev121.dist-info}/RECORD +18 -16
- {omlish-0.0.0.dev119.dist-info → omlish-0.0.0.dev121.dist-info}/LICENSE +0 -0
- {omlish-0.0.0.dev119.dist-info → omlish-0.0.0.dev121.dist-info}/WHEEL +0 -0
- {omlish-0.0.0.dev119.dist-info → omlish-0.0.0.dev121.dist-info}/entry_points.txt +0 -0
- {omlish-0.0.0.dev119.dist-info → omlish-0.0.0.dev121.dist-info}/top_level.txt +0 -0
omlish/__about__.py
CHANGED
omlish/inject/binder.py
CHANGED
omlish/inject/impl/inspect.py
CHANGED
@@ -7,7 +7,6 @@ TODO:
|
|
7
7
|
"""
|
8
8
|
import dataclasses as dc
|
9
9
|
import inspect
|
10
|
-
import types
|
11
10
|
import typing as ta
|
12
11
|
import weakref
|
13
12
|
|
@@ -28,38 +27,38 @@ R = ta.TypeVar('R')
|
|
28
27
|
##
|
29
28
|
|
30
29
|
|
31
|
-
|
30
|
+
_SIGNATURE_CACHE: ta.MutableMapping[ta.Any, inspect.Signature] = weakref.WeakKeyDictionary()
|
32
31
|
|
33
32
|
|
34
33
|
def signature(obj: ta.Any) -> inspect.Signature:
|
35
34
|
try:
|
36
|
-
return
|
35
|
+
return _SIGNATURE_CACHE[obj]
|
37
36
|
except TypeError:
|
38
37
|
return inspect.signature(obj)
|
39
38
|
except KeyError:
|
40
39
|
pass
|
41
40
|
sig = inspect.signature(obj)
|
42
|
-
|
41
|
+
_SIGNATURE_CACHE[obj] = sig
|
43
42
|
return sig
|
44
43
|
|
45
44
|
|
46
45
|
##
|
47
46
|
|
48
47
|
|
49
|
-
|
48
|
+
_TAGS: ta.MutableMapping[ta.Any, dict[str, ta.Any]] = weakref.WeakKeyDictionary()
|
50
49
|
|
51
50
|
|
52
51
|
def tag(obj: T, **kwargs: ta.Any) -> T:
|
53
52
|
for v in kwargs.values():
|
54
53
|
if isinstance(v, Tag):
|
55
54
|
raise TypeError(v)
|
56
|
-
|
55
|
+
_TAGS.setdefault(obj, {}).update(**kwargs)
|
57
56
|
return obj
|
58
57
|
|
59
58
|
|
60
59
|
def tags(**kwargs: ta.Any) -> ta.Callable[[ta.Callable[P, R]], ta.Callable[P, R]]:
|
61
60
|
def inner(obj):
|
62
|
-
|
61
|
+
_TAGS[obj] = kwargs
|
63
62
|
return obj
|
64
63
|
return inner
|
65
64
|
|
@@ -75,7 +74,7 @@ def build_kwargs_target(
|
|
75
74
|
raw_optional: bool = False,
|
76
75
|
) -> KwargsTarget:
|
77
76
|
sig = signature(obj)
|
78
|
-
tags =
|
77
|
+
tags = _TAGS.get(obj)
|
79
78
|
|
80
79
|
seen: set[Key] = set(map(as_key, skip_kwargs)) if skip_kwargs is not None else set()
|
81
80
|
kws: list[Kwarg] = []
|
@@ -92,10 +91,9 @@ def build_kwargs_target(
|
|
92
91
|
if (
|
93
92
|
not raw_optional and
|
94
93
|
isinstance(rf := rfl.type_(ann), rfl.Union) and
|
95
|
-
|
96
|
-
and types.NoneType in rf.args
|
94
|
+
rf.is_optional
|
97
95
|
):
|
98
|
-
|
96
|
+
ann = rf.without_none()
|
99
97
|
|
100
98
|
rty = rfl.type_(ann)
|
101
99
|
|
omlish/lite/cached.py
CHANGED
omlish/lite/contextmanagers.py
CHANGED
@@ -25,8 +25,12 @@ class ExitStacked:
|
|
25
25
|
def __exit__(self, exc_type, exc_val, exc_tb):
|
26
26
|
if (es := self._exit_stack) is None:
|
27
27
|
return None
|
28
|
+
self._exit_contexts()
|
28
29
|
return es.__exit__(exc_type, exc_val, exc_tb)
|
29
30
|
|
31
|
+
def _exit_contexts(self) -> None:
|
32
|
+
pass
|
33
|
+
|
30
34
|
def _enter_context(self, cm: ta.ContextManager[T]) -> T:
|
31
35
|
es = check_not_none(self._exit_stack)
|
32
36
|
return es.enter_context(cm)
|
omlish/lite/inject.py
ADDED
@@ -0,0 +1,624 @@
|
|
1
|
+
# ruff: noqa: UP006 UP007
|
2
|
+
import abc
|
3
|
+
import dataclasses as dc
|
4
|
+
import functools
|
5
|
+
import inspect
|
6
|
+
import types
|
7
|
+
import typing as ta
|
8
|
+
import weakref
|
9
|
+
|
10
|
+
from .check import check_isinstance
|
11
|
+
from .check import check_not_isinstance
|
12
|
+
from .maybes import Maybe
|
13
|
+
from .reflect import get_optional_alias_arg
|
14
|
+
from .reflect import is_optional_alias
|
15
|
+
|
16
|
+
|
17
|
+
T = ta.TypeVar('T')
|
18
|
+
|
19
|
+
InjectorKeyCls = ta.Union[type, ta.NewType]
|
20
|
+
|
21
|
+
InjectorProviderFn = ta.Callable[['Injector'], ta.Any]
|
22
|
+
InjectorProviderFnMap = ta.Mapping['InjectorKey', 'InjectorProviderFn']
|
23
|
+
|
24
|
+
InjectorBindingOrBindings = ta.Union['InjectorBinding', 'InjectorBindings']
|
25
|
+
|
26
|
+
|
27
|
+
###
|
28
|
+
# types
|
29
|
+
|
30
|
+
|
31
|
+
@dc.dataclass(frozen=True)
|
32
|
+
class InjectorKey:
|
33
|
+
cls: InjectorKeyCls
|
34
|
+
tag: ta.Any = None
|
35
|
+
array: bool = False
|
36
|
+
|
37
|
+
|
38
|
+
##
|
39
|
+
|
40
|
+
|
41
|
+
class InjectorProvider(abc.ABC):
|
42
|
+
@abc.abstractmethod
|
43
|
+
def provider_fn(self) -> InjectorProviderFn:
|
44
|
+
raise NotImplementedError
|
45
|
+
|
46
|
+
|
47
|
+
##
|
48
|
+
|
49
|
+
|
50
|
+
@dc.dataclass(frozen=True)
|
51
|
+
class InjectorBinding:
|
52
|
+
key: InjectorKey
|
53
|
+
provider: InjectorProvider
|
54
|
+
|
55
|
+
|
56
|
+
class InjectorBindings(abc.ABC):
|
57
|
+
@abc.abstractmethod
|
58
|
+
def bindings(self) -> ta.Iterator[InjectorBinding]:
|
59
|
+
raise NotImplementedError
|
60
|
+
|
61
|
+
##
|
62
|
+
|
63
|
+
|
64
|
+
class Injector(abc.ABC):
|
65
|
+
@abc.abstractmethod
|
66
|
+
def try_provide(self, key: ta.Any) -> Maybe[ta.Any]:
|
67
|
+
raise NotImplementedError
|
68
|
+
|
69
|
+
@abc.abstractmethod
|
70
|
+
def provide(self, key: ta.Any) -> ta.Any:
|
71
|
+
raise NotImplementedError
|
72
|
+
|
73
|
+
@abc.abstractmethod
|
74
|
+
def provide_kwargs(self, obj: ta.Any) -> ta.Mapping[str, ta.Any]:
|
75
|
+
raise NotImplementedError
|
76
|
+
|
77
|
+
@abc.abstractmethod
|
78
|
+
def inject(self, obj: ta.Any) -> ta.Any:
|
79
|
+
raise NotImplementedError
|
80
|
+
|
81
|
+
|
82
|
+
###
|
83
|
+
# exceptions
|
84
|
+
|
85
|
+
|
86
|
+
@dc.dataclass(frozen=True)
|
87
|
+
class InjectorKeyError(Exception):
|
88
|
+
key: InjectorKey
|
89
|
+
|
90
|
+
source: ta.Any = None
|
91
|
+
name: ta.Optional[str] = None
|
92
|
+
|
93
|
+
|
94
|
+
@dc.dataclass(frozen=True)
|
95
|
+
class UnboundInjectorKeyError(InjectorKeyError):
|
96
|
+
pass
|
97
|
+
|
98
|
+
|
99
|
+
@dc.dataclass(frozen=True)
|
100
|
+
class DuplicateInjectorKeyError(InjectorKeyError):
|
101
|
+
pass
|
102
|
+
|
103
|
+
|
104
|
+
###
|
105
|
+
# keys
|
106
|
+
|
107
|
+
|
108
|
+
def as_injector_key(o: ta.Any) -> InjectorKey:
|
109
|
+
if o is inspect.Parameter.empty:
|
110
|
+
raise TypeError(o)
|
111
|
+
if isinstance(o, InjectorKey):
|
112
|
+
return o
|
113
|
+
if isinstance(o, (type, ta.NewType)):
|
114
|
+
return InjectorKey(o)
|
115
|
+
raise TypeError(o)
|
116
|
+
|
117
|
+
|
118
|
+
###
|
119
|
+
# providers
|
120
|
+
|
121
|
+
|
122
|
+
@dc.dataclass(frozen=True)
|
123
|
+
class FnInjectorProvider(InjectorProvider):
|
124
|
+
fn: ta.Any
|
125
|
+
|
126
|
+
def __post_init__(self) -> None:
|
127
|
+
check_not_isinstance(self.fn, type)
|
128
|
+
|
129
|
+
def provider_fn(self) -> InjectorProviderFn:
|
130
|
+
def pfn(i: Injector) -> ta.Any:
|
131
|
+
return i.inject(self.fn)
|
132
|
+
|
133
|
+
return pfn
|
134
|
+
|
135
|
+
|
136
|
+
@dc.dataclass(frozen=True)
|
137
|
+
class CtorInjectorProvider(InjectorProvider):
|
138
|
+
cls: type
|
139
|
+
|
140
|
+
def __post_init__(self) -> None:
|
141
|
+
check_isinstance(self.cls, type)
|
142
|
+
|
143
|
+
def provider_fn(self) -> InjectorProviderFn:
|
144
|
+
def pfn(i: Injector) -> ta.Any:
|
145
|
+
return i.inject(self.cls)
|
146
|
+
|
147
|
+
return pfn
|
148
|
+
|
149
|
+
|
150
|
+
@dc.dataclass(frozen=True)
|
151
|
+
class ConstInjectorProvider(InjectorProvider):
|
152
|
+
v: ta.Any
|
153
|
+
|
154
|
+
def provider_fn(self) -> InjectorProviderFn:
|
155
|
+
return lambda _: self.v
|
156
|
+
|
157
|
+
|
158
|
+
@dc.dataclass(frozen=True)
|
159
|
+
class SingletonInjectorProvider(InjectorProvider):
|
160
|
+
p: InjectorProvider
|
161
|
+
|
162
|
+
def __post_init__(self) -> None:
|
163
|
+
check_isinstance(self.p, InjectorProvider)
|
164
|
+
|
165
|
+
def provider_fn(self) -> InjectorProviderFn:
|
166
|
+
v = not_set = object()
|
167
|
+
|
168
|
+
def pfn(i: Injector) -> ta.Any:
|
169
|
+
nonlocal v
|
170
|
+
if v is not_set:
|
171
|
+
v = ufn(i)
|
172
|
+
return v
|
173
|
+
|
174
|
+
ufn = self.p.provider_fn()
|
175
|
+
return pfn
|
176
|
+
|
177
|
+
|
178
|
+
@dc.dataclass(frozen=True)
|
179
|
+
class LinkInjectorProvider(InjectorProvider):
|
180
|
+
k: InjectorKey
|
181
|
+
|
182
|
+
def __post_init__(self) -> None:
|
183
|
+
check_isinstance(self.k, InjectorKey)
|
184
|
+
|
185
|
+
def provider_fn(self) -> InjectorProviderFn:
|
186
|
+
def pfn(i: Injector) -> ta.Any:
|
187
|
+
return i.provide(self.k)
|
188
|
+
|
189
|
+
return pfn
|
190
|
+
|
191
|
+
|
192
|
+
@dc.dataclass(frozen=True)
|
193
|
+
class ArrayInjectorProvider(InjectorProvider):
|
194
|
+
ps: ta.Sequence[InjectorProvider]
|
195
|
+
|
196
|
+
def provider_fn(self) -> InjectorProviderFn:
|
197
|
+
ps = [p.provider_fn() for p in self.ps]
|
198
|
+
|
199
|
+
def pfn(i: Injector) -> ta.Any:
|
200
|
+
rv = []
|
201
|
+
for ep in ps:
|
202
|
+
o = ep(i)
|
203
|
+
rv.append(o)
|
204
|
+
return rv
|
205
|
+
|
206
|
+
return pfn
|
207
|
+
|
208
|
+
|
209
|
+
###
|
210
|
+
# bindings
|
211
|
+
|
212
|
+
|
213
|
+
@dc.dataclass(frozen=True)
|
214
|
+
class _InjectorBindings(InjectorBindings):
|
215
|
+
bs: ta.Optional[ta.Sequence[InjectorBinding]] = None
|
216
|
+
ps: ta.Optional[ta.Sequence[InjectorBindings]] = None
|
217
|
+
|
218
|
+
def bindings(self) -> ta.Iterator[InjectorBinding]:
|
219
|
+
if self.bs is not None:
|
220
|
+
yield from self.bs
|
221
|
+
if self.ps is not None:
|
222
|
+
for p in self.ps:
|
223
|
+
yield from p.bindings()
|
224
|
+
|
225
|
+
|
226
|
+
def as_injector_bindings(*args: InjectorBindingOrBindings) -> InjectorBindings:
|
227
|
+
bs: ta.List[InjectorBinding] = []
|
228
|
+
ps: ta.List[InjectorBindings] = []
|
229
|
+
for a in args:
|
230
|
+
if isinstance(a, InjectorBindings):
|
231
|
+
ps.append(a)
|
232
|
+
elif isinstance(a, InjectorBinding):
|
233
|
+
bs.append(a)
|
234
|
+
else:
|
235
|
+
raise TypeError(a)
|
236
|
+
return _InjectorBindings(
|
237
|
+
bs or None,
|
238
|
+
ps or None,
|
239
|
+
)
|
240
|
+
|
241
|
+
|
242
|
+
##
|
243
|
+
|
244
|
+
|
245
|
+
@dc.dataclass(frozen=True)
|
246
|
+
class OverridesInjectorBindings(InjectorBindings):
|
247
|
+
p: InjectorBindings
|
248
|
+
m: ta.Mapping[InjectorKey, InjectorBinding]
|
249
|
+
|
250
|
+
def bindings(self) -> ta.Iterator[InjectorBinding]:
|
251
|
+
for b in self.p.bindings():
|
252
|
+
yield self.m.get(b.key, b)
|
253
|
+
|
254
|
+
|
255
|
+
def injector_override(p: InjectorBindings, *args: InjectorBindingOrBindings) -> InjectorBindings:
|
256
|
+
m: ta.Dict[InjectorKey, InjectorBinding] = {}
|
257
|
+
for b in as_injector_bindings(*args).bindings():
|
258
|
+
if b.key in m:
|
259
|
+
raise DuplicateInjectorKeyError(b.key)
|
260
|
+
m[b.key] = b
|
261
|
+
return OverridesInjectorBindings(p, m)
|
262
|
+
|
263
|
+
|
264
|
+
##
|
265
|
+
|
266
|
+
|
267
|
+
def build_injector_provider_map(bs: InjectorBindings) -> ta.Mapping[InjectorKey, InjectorProvider]:
|
268
|
+
pm: ta.Dict[InjectorKey, InjectorProvider] = {}
|
269
|
+
am: ta.Dict[InjectorKey, ta.List[InjectorProvider]] = {}
|
270
|
+
|
271
|
+
for b in bs.bindings():
|
272
|
+
if b.key.array:
|
273
|
+
am.setdefault(b.key, []).append(b.provider)
|
274
|
+
else:
|
275
|
+
if b.key in pm:
|
276
|
+
raise KeyError(b.key)
|
277
|
+
pm[b.key] = b.provider
|
278
|
+
|
279
|
+
if am:
|
280
|
+
for k, aps in am.items():
|
281
|
+
pm[k] = ArrayInjectorProvider(aps)
|
282
|
+
|
283
|
+
return pm
|
284
|
+
|
285
|
+
|
286
|
+
###
|
287
|
+
# inspection
|
288
|
+
|
289
|
+
|
290
|
+
_INJECTION_SIGNATURE_CACHE: ta.MutableMapping[ta.Any, inspect.Signature] = weakref.WeakKeyDictionary()
|
291
|
+
|
292
|
+
|
293
|
+
def _injection_signature(obj: ta.Any) -> inspect.Signature:
|
294
|
+
try:
|
295
|
+
return _INJECTION_SIGNATURE_CACHE[obj]
|
296
|
+
except TypeError:
|
297
|
+
return inspect.signature(obj)
|
298
|
+
except KeyError:
|
299
|
+
pass
|
300
|
+
sig = inspect.signature(obj)
|
301
|
+
_INJECTION_SIGNATURE_CACHE[obj] = sig
|
302
|
+
return sig
|
303
|
+
|
304
|
+
|
305
|
+
class InjectionKwarg(ta.NamedTuple):
|
306
|
+
name: str
|
307
|
+
key: InjectorKey
|
308
|
+
has_default: bool
|
309
|
+
|
310
|
+
|
311
|
+
class InjectionKwargsTarget(ta.NamedTuple):
|
312
|
+
obj: ta.Any
|
313
|
+
kwargs: ta.Sequence[InjectionKwarg]
|
314
|
+
|
315
|
+
|
316
|
+
def build_injection_kwargs_target(
|
317
|
+
obj: ta.Any,
|
318
|
+
*,
|
319
|
+
skip_args: int = 0,
|
320
|
+
skip_kwargs: ta.Optional[ta.Iterable[ta.Any]] = None,
|
321
|
+
raw_optional: bool = False,
|
322
|
+
) -> InjectionKwargsTarget:
|
323
|
+
sig = _injection_signature(obj)
|
324
|
+
|
325
|
+
seen: ta.Set[InjectorKey] = set(map(as_injector_key, skip_kwargs)) if skip_kwargs is not None else set()
|
326
|
+
kws: ta.List[InjectionKwarg] = []
|
327
|
+
for p in list(sig.parameters.values())[skip_args:]:
|
328
|
+
if p.annotation is inspect.Signature.empty:
|
329
|
+
if p.default is not inspect.Parameter.empty:
|
330
|
+
raise KeyError(f'{obj}, {p.name}')
|
331
|
+
continue
|
332
|
+
|
333
|
+
if p.kind not in (inspect.Parameter.POSITIONAL_OR_KEYWORD, inspect.Parameter.KEYWORD_ONLY):
|
334
|
+
raise TypeError(sig)
|
335
|
+
|
336
|
+
ann = p.annotation
|
337
|
+
if (
|
338
|
+
not raw_optional and
|
339
|
+
is_optional_alias(ann)
|
340
|
+
):
|
341
|
+
ann = get_optional_alias_arg(ann)
|
342
|
+
|
343
|
+
k = as_injector_key(ann)
|
344
|
+
|
345
|
+
if k in seen:
|
346
|
+
raise DuplicateInjectorKeyError(k)
|
347
|
+
seen.add(k)
|
348
|
+
|
349
|
+
kws.append(InjectionKwarg(
|
350
|
+
p.name,
|
351
|
+
k,
|
352
|
+
p.default is not inspect.Parameter.empty,
|
353
|
+
))
|
354
|
+
|
355
|
+
return InjectionKwargsTarget(
|
356
|
+
obj,
|
357
|
+
kws,
|
358
|
+
)
|
359
|
+
|
360
|
+
|
361
|
+
###
|
362
|
+
# binder
|
363
|
+
|
364
|
+
|
365
|
+
class InjectorBinder:
|
366
|
+
def __new__(cls, *args, **kwargs): # noqa
|
367
|
+
raise TypeError
|
368
|
+
|
369
|
+
_FN_TYPES: ta.Tuple[type, ...] = (
|
370
|
+
types.FunctionType,
|
371
|
+
types.MethodType,
|
372
|
+
|
373
|
+
classmethod,
|
374
|
+
staticmethod,
|
375
|
+
|
376
|
+
functools.partial,
|
377
|
+
functools.partialmethod,
|
378
|
+
)
|
379
|
+
|
380
|
+
@classmethod
|
381
|
+
def _is_fn(cls, obj: ta.Any) -> bool:
|
382
|
+
return isinstance(obj, cls._FN_TYPES)
|
383
|
+
|
384
|
+
@classmethod
|
385
|
+
def bind_as_fn(cls, icls: ta.Type[T]) -> ta.Type[T]:
|
386
|
+
check_isinstance(icls, type)
|
387
|
+
if icls not in cls._FN_TYPES:
|
388
|
+
cls._FN_TYPES = (*cls._FN_TYPES, icls)
|
389
|
+
return icls
|
390
|
+
|
391
|
+
_BANNED_BIND_TYPES: ta.Tuple[type, ...] = (
|
392
|
+
InjectorProvider,
|
393
|
+
)
|
394
|
+
|
395
|
+
@classmethod
|
396
|
+
def bind(
|
397
|
+
cls,
|
398
|
+
obj: ta.Any,
|
399
|
+
*,
|
400
|
+
key: ta.Any = None,
|
401
|
+
tag: ta.Any = None,
|
402
|
+
array: ta.Optional[bool] = None, # noqa
|
403
|
+
|
404
|
+
to_fn: ta.Any = None,
|
405
|
+
to_ctor: ta.Any = None,
|
406
|
+
to_const: ta.Any = None,
|
407
|
+
to_key: ta.Any = None,
|
408
|
+
|
409
|
+
singleton: bool = False,
|
410
|
+
) -> InjectorBinding:
|
411
|
+
if obj is None or obj is inspect.Parameter.empty:
|
412
|
+
raise TypeError(obj)
|
413
|
+
if isinstance(obj, cls._BANNED_BIND_TYPES):
|
414
|
+
raise TypeError(obj)
|
415
|
+
|
416
|
+
##
|
417
|
+
|
418
|
+
if key is not None:
|
419
|
+
key = as_injector_key(key)
|
420
|
+
|
421
|
+
##
|
422
|
+
|
423
|
+
has_to = (
|
424
|
+
to_fn is not None or
|
425
|
+
to_ctor is not None or
|
426
|
+
to_const is not None or
|
427
|
+
to_key is not None
|
428
|
+
)
|
429
|
+
if isinstance(obj, InjectorKey):
|
430
|
+
if key is None:
|
431
|
+
key = obj
|
432
|
+
elif isinstance(obj, type):
|
433
|
+
if not has_to:
|
434
|
+
to_ctor = obj
|
435
|
+
if key is None:
|
436
|
+
key = InjectorKey(obj)
|
437
|
+
elif cls._is_fn(obj) and not has_to:
|
438
|
+
to_fn = obj
|
439
|
+
if key is None:
|
440
|
+
sig = _injection_signature(obj)
|
441
|
+
ty = check_isinstance(sig.return_annotation, type)
|
442
|
+
key = InjectorKey(ty)
|
443
|
+
else:
|
444
|
+
if to_const is not None:
|
445
|
+
raise TypeError('Cannot bind instance with to_const')
|
446
|
+
to_const = obj
|
447
|
+
if key is None:
|
448
|
+
key = InjectorKey(type(obj))
|
449
|
+
del has_to
|
450
|
+
|
451
|
+
##
|
452
|
+
|
453
|
+
if tag is not None:
|
454
|
+
if key.tag is not None:
|
455
|
+
raise TypeError('Tag already set')
|
456
|
+
key = dc.replace(key, tag=tag)
|
457
|
+
|
458
|
+
if array is not None:
|
459
|
+
key = dc.replace(key, array=array)
|
460
|
+
|
461
|
+
##
|
462
|
+
|
463
|
+
providers: ta.List[InjectorProvider] = []
|
464
|
+
if to_fn is not None:
|
465
|
+
providers.append(FnInjectorProvider(to_fn))
|
466
|
+
if to_ctor is not None:
|
467
|
+
providers.append(CtorInjectorProvider(to_ctor))
|
468
|
+
if to_const is not None:
|
469
|
+
providers.append(ConstInjectorProvider(to_const))
|
470
|
+
if to_key is not None:
|
471
|
+
providers.append(LinkInjectorProvider(as_injector_key(to_key)))
|
472
|
+
if not providers:
|
473
|
+
raise TypeError('Must specify provider')
|
474
|
+
if len(providers) > 1:
|
475
|
+
raise TypeError('May not specify multiple providers')
|
476
|
+
provider, = providers
|
477
|
+
|
478
|
+
##
|
479
|
+
|
480
|
+
if singleton:
|
481
|
+
provider = SingletonInjectorProvider(provider)
|
482
|
+
|
483
|
+
##
|
484
|
+
|
485
|
+
binding = InjectorBinding(key, provider)
|
486
|
+
|
487
|
+
##
|
488
|
+
|
489
|
+
return binding
|
490
|
+
|
491
|
+
|
492
|
+
###
|
493
|
+
# injector
|
494
|
+
|
495
|
+
|
496
|
+
_INJECTOR_INJECTOR_KEY = InjectorKey(Injector)
|
497
|
+
|
498
|
+
|
499
|
+
class _Injector(Injector):
|
500
|
+
def __init__(self, bs: InjectorBindings, p: ta.Optional[Injector] = None) -> None:
|
501
|
+
super().__init__()
|
502
|
+
|
503
|
+
self._bs = check_isinstance(bs, InjectorBindings)
|
504
|
+
self._p: ta.Optional[Injector] = check_isinstance(p, (Injector, type(None)))
|
505
|
+
|
506
|
+
self._pfm = {k: v.provider_fn() for k, v in build_injector_provider_map(bs).items()}
|
507
|
+
|
508
|
+
if _INJECTOR_INJECTOR_KEY in self._pfm:
|
509
|
+
raise DuplicateInjectorKeyError(_INJECTOR_INJECTOR_KEY)
|
510
|
+
|
511
|
+
def try_provide(self, key: ta.Any) -> Maybe[ta.Any]:
|
512
|
+
key = as_injector_key(key)
|
513
|
+
|
514
|
+
if key == _INJECTOR_INJECTOR_KEY:
|
515
|
+
return Maybe.just(self)
|
516
|
+
|
517
|
+
fn = self._pfm.get(key)
|
518
|
+
if fn is not None:
|
519
|
+
return Maybe.just(fn(self))
|
520
|
+
|
521
|
+
if self._p is not None:
|
522
|
+
pv = self._p.try_provide(key)
|
523
|
+
if pv is not None:
|
524
|
+
return Maybe.empty()
|
525
|
+
|
526
|
+
return Maybe.empty()
|
527
|
+
|
528
|
+
def provide(self, key: ta.Any) -> ta.Any:
|
529
|
+
v = self.try_provide(key)
|
530
|
+
if v.present:
|
531
|
+
return v.must()
|
532
|
+
raise UnboundInjectorKeyError(key)
|
533
|
+
|
534
|
+
def provide_kwargs(self, obj: ta.Any) -> ta.Mapping[str, ta.Any]:
|
535
|
+
kt = build_injection_kwargs_target(obj)
|
536
|
+
ret: ta.Dict[str, ta.Any] = {}
|
537
|
+
for kw in kt.kwargs:
|
538
|
+
if kw.has_default:
|
539
|
+
if not (mv := self.try_provide(kw.key)).present:
|
540
|
+
continue
|
541
|
+
v = mv.must()
|
542
|
+
else:
|
543
|
+
v = self.provide(kw.key)
|
544
|
+
ret[kw.name] = v
|
545
|
+
return ret
|
546
|
+
|
547
|
+
def inject(self, obj: ta.Any) -> ta.Any:
|
548
|
+
kws = self.provide_kwargs(obj)
|
549
|
+
return obj(**kws)
|
550
|
+
|
551
|
+
|
552
|
+
###
|
553
|
+
# injection helpers
|
554
|
+
|
555
|
+
|
556
|
+
class Injection:
|
557
|
+
def __new__(cls, *args, **kwargs): # noqa
|
558
|
+
raise TypeError
|
559
|
+
|
560
|
+
# keys
|
561
|
+
|
562
|
+
@classmethod
|
563
|
+
def as_key(cls, o: ta.Any) -> InjectorKey:
|
564
|
+
return as_injector_key(o)
|
565
|
+
|
566
|
+
@classmethod
|
567
|
+
def array(cls, o: ta.Any) -> InjectorKey:
|
568
|
+
return dc.replace(as_injector_key(o), array=True)
|
569
|
+
|
570
|
+
@classmethod
|
571
|
+
def tag(cls, o: ta.Any, t: ta.Any) -> InjectorKey:
|
572
|
+
return dc.replace(as_injector_key(o), tag=t)
|
573
|
+
|
574
|
+
# bindings
|
575
|
+
|
576
|
+
@classmethod
|
577
|
+
def as_bindings(cls, *args: InjectorBindingOrBindings) -> InjectorBindings:
|
578
|
+
return as_injector_bindings(*args)
|
579
|
+
|
580
|
+
@classmethod
|
581
|
+
def override(cls, p: InjectorBindings, *args: InjectorBindingOrBindings) -> InjectorBindings:
|
582
|
+
return injector_override(p, *args)
|
583
|
+
|
584
|
+
# binder
|
585
|
+
|
586
|
+
@classmethod
|
587
|
+
def bind(
|
588
|
+
cls,
|
589
|
+
obj: ta.Any,
|
590
|
+
*,
|
591
|
+
key: ta.Any = None,
|
592
|
+
tag: ta.Any = None,
|
593
|
+
array: ta.Optional[bool] = None, # noqa
|
594
|
+
|
595
|
+
to_fn: ta.Any = None,
|
596
|
+
to_ctor: ta.Any = None,
|
597
|
+
to_const: ta.Any = None,
|
598
|
+
to_key: ta.Any = None,
|
599
|
+
|
600
|
+
singleton: bool = False,
|
601
|
+
) -> InjectorBinding:
|
602
|
+
return InjectorBinder.bind(
|
603
|
+
obj,
|
604
|
+
|
605
|
+
key=key,
|
606
|
+
tag=tag,
|
607
|
+
array=array,
|
608
|
+
|
609
|
+
to_fn=to_fn,
|
610
|
+
to_ctor=to_ctor,
|
611
|
+
to_const=to_const,
|
612
|
+
to_key=to_key,
|
613
|
+
|
614
|
+
singleton=singleton,
|
615
|
+
)
|
616
|
+
|
617
|
+
# injector
|
618
|
+
|
619
|
+
@classmethod
|
620
|
+
def create_injector(cls, *args: InjectorBindingOrBindings, p: ta.Optional[Injector] = None) -> Injector:
|
621
|
+
return _Injector(as_injector_bindings(*args), p)
|
622
|
+
|
623
|
+
|
624
|
+
inj = Injection
|
omlish/lite/maybes.py
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
import abc
|
2
|
+
import typing as ta
|
3
|
+
|
4
|
+
|
5
|
+
T = ta.TypeVar('T')
|
6
|
+
|
7
|
+
|
8
|
+
class Maybe(ta.Generic[T]):
|
9
|
+
@property
|
10
|
+
@abc.abstractmethod
|
11
|
+
def present(self) -> bool:
|
12
|
+
raise NotImplementedError
|
13
|
+
|
14
|
+
@abc.abstractmethod
|
15
|
+
def must(self) -> T:
|
16
|
+
raise NotImplementedError
|
17
|
+
|
18
|
+
@classmethod
|
19
|
+
def just(cls, v: T) -> 'Maybe[T]':
|
20
|
+
return tuple.__new__(_Maybe, (v,)) # noqa
|
21
|
+
|
22
|
+
_empty: ta.ClassVar['Maybe']
|
23
|
+
|
24
|
+
@classmethod
|
25
|
+
def empty(cls) -> 'Maybe[T]':
|
26
|
+
return Maybe._empty
|
27
|
+
|
28
|
+
|
29
|
+
class _Maybe(Maybe[T], tuple):
|
30
|
+
__slots__ = ()
|
31
|
+
|
32
|
+
def __init_subclass__(cls, **kwargs):
|
33
|
+
raise TypeError
|
34
|
+
|
35
|
+
@property
|
36
|
+
def present(self) -> bool:
|
37
|
+
return bool(self)
|
38
|
+
|
39
|
+
def must(self) -> T:
|
40
|
+
if not self:
|
41
|
+
raise ValueError
|
42
|
+
return self[0]
|
43
|
+
|
44
|
+
|
45
|
+
Maybe._empty = tuple.__new__(_Maybe, ()) # noqa
|
@@ -1,6 +1,10 @@
|
|
1
1
|
"""
|
2
2
|
TODO:
|
3
|
-
- @omlish-lite
|
3
|
+
- @omlish-lite ?
|
4
|
+
- 'recipes'
|
5
|
+
- abstract runtime
|
6
|
+
- https://github.com/wrmsr/omnibus/blob/c2ff67b6c5c80aa03fe27a9b6f36212f3212c7ca/omnibus/jmespath/eval.py#L64
|
7
|
+
- pytest-ify
|
4
8
|
|
5
9
|
Applied:
|
6
10
|
https://github.com/jmespath-community/python-jmespath/compare/bbe7300c60056f52413603cf3e2bcd0b6afeda3d...aef45e9d665de662eee31b06aeb8261e2bc8b90a
|
omlish/specs/jmespath/ast.py
CHANGED
@@ -20,9 +20,15 @@ class LeafNode(Node, lang.Abstract):
|
|
20
20
|
return []
|
21
21
|
|
22
22
|
|
23
|
+
UnaryArithmeticOperator: ta.TypeAlias = ta.Literal[
|
24
|
+
'plus',
|
25
|
+
'minus',
|
26
|
+
]
|
27
|
+
|
28
|
+
|
23
29
|
@dc.dataclass(frozen=True)
|
24
30
|
class ArithmeticUnary(Node, lang.Final):
|
25
|
-
operator:
|
31
|
+
operator: UnaryArithmeticOperator
|
26
32
|
expression: Node
|
27
33
|
|
28
34
|
@property
|
@@ -30,9 +36,19 @@ class ArithmeticUnary(Node, lang.Final):
|
|
30
36
|
return [self.expression]
|
31
37
|
|
32
38
|
|
39
|
+
ArithmeticOperator: ta.TypeAlias = ta.Literal[
|
40
|
+
'div',
|
41
|
+
'divide',
|
42
|
+
'minus',
|
43
|
+
'modulo',
|
44
|
+
'multiply',
|
45
|
+
'plus',
|
46
|
+
]
|
47
|
+
|
48
|
+
|
33
49
|
@dc.dataclass(frozen=True)
|
34
50
|
class Arithmetic(Node, lang.Final):
|
35
|
-
operator:
|
51
|
+
operator: ArithmeticOperator
|
36
52
|
left: Node
|
37
53
|
right: Node
|
38
54
|
|
@@ -51,9 +67,19 @@ class Assign(Node, lang.Final):
|
|
51
67
|
return [self.expr]
|
52
68
|
|
53
69
|
|
70
|
+
ComparatorName: ta.TypeAlias = ta.Literal[
|
71
|
+
'eq',
|
72
|
+
'ne',
|
73
|
+
'lt',
|
74
|
+
'gt',
|
75
|
+
'lte',
|
76
|
+
'gte',
|
77
|
+
]
|
78
|
+
|
79
|
+
|
54
80
|
@dc.dataclass(frozen=True)
|
55
81
|
class Comparator(Node, lang.Final):
|
56
|
-
name:
|
82
|
+
name: ComparatorName
|
57
83
|
first: Node
|
58
84
|
second: Node
|
59
85
|
|
@@ -638,6 +638,14 @@ class ObjectFunctions(FunctionsClass):
|
|
638
638
|
def _func_values(self, arg):
|
639
639
|
return list(arg.values())
|
640
640
|
|
641
|
+
@signature({'types': ['expref']}, {'types': ['object']})
|
642
|
+
def _func_filter_keys(self, expref, arg):
|
643
|
+
return {k: v for k, v in arg.items() if expref.visit(expref.expression, k)}
|
644
|
+
|
645
|
+
@signature({'types': ['expref']}, {'types': ['object']})
|
646
|
+
def _func_filter_values(self, expref, arg):
|
647
|
+
return {k: v for k, v in arg.items() if expref.visit(expref.expression, v)}
|
648
|
+
|
641
649
|
|
642
650
|
class KeyedFunctions(FunctionsClass):
|
643
651
|
def _create_key_func(self, expref, allowed_types, function_name):
|
omlish/specs/jmespath/parser.py
CHANGED
@@ -27,9 +27,11 @@ import typing as ta
|
|
27
27
|
from ... import check
|
28
28
|
from .ast import AndExpression
|
29
29
|
from .ast import Arithmetic
|
30
|
+
from .ast import ArithmeticOperator
|
30
31
|
from .ast import ArithmeticUnary
|
31
32
|
from .ast import Assign
|
32
33
|
from .ast import Comparator
|
34
|
+
from .ast import ComparatorName
|
33
35
|
from .ast import CurrentNode
|
34
36
|
from .ast import Expref
|
35
37
|
from .ast import Field
|
@@ -52,6 +54,7 @@ from .ast import Projection
|
|
52
54
|
from .ast import RootNode
|
53
55
|
from .ast import Slice
|
54
56
|
from .ast import Subexpression
|
57
|
+
from .ast import UnaryArithmeticOperator
|
55
58
|
from .ast import ValueProjection
|
56
59
|
from .ast import VariableRef
|
57
60
|
from .exceptions import IncompleteExpressionError
|
@@ -491,15 +494,15 @@ class Parser:
|
|
491
494
|
|
492
495
|
def _parse_comparator(self, left: Node, comparator: str) -> Node:
|
493
496
|
right = self._expression(self.BINDING_POWER[comparator])
|
494
|
-
return Comparator(comparator, left, right)
|
497
|
+
return Comparator(ta.cast(ComparatorName, comparator), left, right)
|
495
498
|
|
496
499
|
def _parse_arithmetic_unary(self, token: Token) -> Node:
|
497
500
|
expression = self._expression(self.BINDING_POWER[token['type']])
|
498
|
-
return ArithmeticUnary(token['type'], expression)
|
501
|
+
return ArithmeticUnary(ta.cast(UnaryArithmeticOperator, token['type']), expression)
|
499
502
|
|
500
503
|
def _parse_arithmetic(self, left: Node, operator: str) -> Node:
|
501
504
|
right = self._expression(self.BINDING_POWER[operator])
|
502
|
-
return Arithmetic(operator, left, right)
|
505
|
+
return Arithmetic(ta.cast(ArithmeticOperator, operator), left, right)
|
503
506
|
|
504
507
|
def _parse_multi_select_list(self) -> Node:
|
505
508
|
expressions: list[Node] = []
|
omlish/specs/jmespath/visitor.py
CHANGED
@@ -6,9 +6,11 @@ from ... import check
|
|
6
6
|
from ... import lang
|
7
7
|
from .ast import AndExpression
|
8
8
|
from .ast import Arithmetic
|
9
|
+
from .ast import ArithmeticOperator
|
9
10
|
from .ast import ArithmeticUnary
|
10
11
|
from .ast import Assign
|
11
12
|
from .ast import Comparator
|
13
|
+
from .ast import ComparatorName
|
12
14
|
from .ast import CurrentNode
|
13
15
|
from .ast import Expref
|
14
16
|
from .ast import Field
|
@@ -31,6 +33,7 @@ from .ast import Projection
|
|
31
33
|
from .ast import RootNode
|
32
34
|
from .ast import Slice
|
33
35
|
from .ast import Subexpression
|
36
|
+
from .ast import UnaryArithmeticOperator
|
34
37
|
from .ast import ValueProjection
|
35
38
|
from .ast import VariableRef
|
36
39
|
from .exceptions import UndefinedVariableError
|
@@ -164,7 +167,7 @@ class _Expression:
|
|
164
167
|
|
165
168
|
|
166
169
|
class TreeInterpreter(Visitor):
|
167
|
-
|
170
|
+
_COMPARATOR_FUNC: ta.Mapping[ComparatorName, ta.Callable] = {
|
168
171
|
'eq': _equals,
|
169
172
|
'ne': lambda x, y: not _equals(x, y),
|
170
173
|
'lt': operator.lt,
|
@@ -173,17 +176,12 @@ class TreeInterpreter(Visitor):
|
|
173
176
|
'gte': operator.ge,
|
174
177
|
}
|
175
178
|
|
176
|
-
_EQUALITY_OPS: ta.AbstractSet[
|
179
|
+
_EQUALITY_OPS: ta.AbstractSet[ComparatorName] = {
|
177
180
|
'eq',
|
178
181
|
'ne',
|
179
182
|
}
|
180
183
|
|
181
|
-
|
182
|
-
'minus': operator.neg,
|
183
|
-
'plus': lambda x: x,
|
184
|
-
}
|
185
|
-
|
186
|
-
_ARITHMETIC_FUNC: ta.Mapping[str, ta.Callable] = {
|
184
|
+
_ARITHMETIC_FUNC: ta.Mapping[ArithmeticOperator, ta.Callable] = {
|
187
185
|
'div': operator.floordiv,
|
188
186
|
'divide': operator.truediv,
|
189
187
|
'minus': operator.sub,
|
@@ -192,6 +190,11 @@ class TreeInterpreter(Visitor):
|
|
192
190
|
'plus': operator.add,
|
193
191
|
}
|
194
192
|
|
193
|
+
_ARITHMETIC_UNARY_FUNC: ta.Mapping[UnaryArithmeticOperator, ta.Callable] = {
|
194
|
+
'minus': operator.neg,
|
195
|
+
'plus': lambda x: x,
|
196
|
+
}
|
197
|
+
|
195
198
|
def __init__(self, options: Options | None = None) -> None:
|
196
199
|
super().__init__()
|
197
200
|
|
@@ -235,7 +238,7 @@ class TreeInterpreter(Visitor):
|
|
235
238
|
|
236
239
|
def visit_comparator(self, node: Comparator, value: ta.Any) -> ta.Any:
|
237
240
|
# Common case: comparator is == or !=
|
238
|
-
comparator_func = self.
|
241
|
+
comparator_func = self._COMPARATOR_FUNC[node.name]
|
239
242
|
if node.name in self._EQUALITY_OPS:
|
240
243
|
return comparator_func(
|
241
244
|
self.visit(node.first, value),
|
@@ -1,5 +1,5 @@
|
|
1
1
|
omlish/.manifests.json,sha256=CxGnj-UiRPlZgmgWoovDWrOnqpSEmBy_kqA7cdfSA3w,1431
|
2
|
-
omlish/__about__.py,sha256=
|
2
|
+
omlish/__about__.py,sha256=aTRzdXeouYEQLsJZyhmeZxxg3aaQgoLMDv_T3jZ_HZE,3352
|
3
3
|
omlish/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
4
4
|
omlish/argparse.py,sha256=cqKGAqcxuxv_s62z0gq29L9KAvg_3-_rFvXKjVpRJjo,8126
|
5
5
|
omlish/c3.py,sha256=4vogWgwPb8TbNS2KkZxpoWbwjj7MuHG2lQG-hdtkvjI,8062
|
@@ -232,7 +232,7 @@ omlish/http/sessions.py,sha256=VZ_WS5uiQG5y7i3u8oKuQMqf8dPKUOjFm_qk_0OvI8c,4793
|
|
232
232
|
omlish/http/sse.py,sha256=MDs9RvxQXoQliImcc6qK1ERajEYM7Q1l8xmr-9ceNBc,2315
|
233
233
|
omlish/http/wsgi.py,sha256=czZsVUX-l2YTlMrUjKN49wRoP4rVpS0qpeBn4O5BoMY,948
|
234
234
|
omlish/inject/__init__.py,sha256=JQ7x8l9MjU-kJ5ap7cPVq7SY7zbbCIrjyJAF0UeE5-s,1886
|
235
|
-
omlish/inject/binder.py,sha256=
|
235
|
+
omlish/inject/binder.py,sha256=DAbc8TZi5w8Mna0TUtq0mT4jeDVA7i7SlBtOFrh2swc,4185
|
236
236
|
omlish/inject/bindings.py,sha256=pLXn2U3kvmAS-68IOG-tr77DbiI-wp9hGyy4lhG6_H8,525
|
237
237
|
omlish/inject/eagers.py,sha256=5AkGYuwijG0ihsH9NSaZotggalJ5_xWXhHE9mkn6IBA,329
|
238
238
|
omlish/inject/elements.py,sha256=BzTnkNS-3iAMI47LMC2543u6A8Tfk3aJXn3CO191ez4,1547
|
@@ -254,7 +254,7 @@ omlish/inject/impl/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuF
|
|
254
254
|
omlish/inject/impl/bindings.py,sha256=8H586RCgmvwq53XBL9WMbb-1-Tdw_hh9zxIDCwcHA1c,414
|
255
255
|
omlish/inject/impl/elements.py,sha256=bJBbHce_eZyIua2wbcejMwd9Uv-QeYcQ-c5N1qOXSmU,5950
|
256
256
|
omlish/inject/impl/injector.py,sha256=WxIVOF6zvipb44302_j-xQZt8vnNCY0gdLX6UWzslXI,7550
|
257
|
-
omlish/inject/impl/inspect.py,sha256=
|
257
|
+
omlish/inject/impl/inspect.py,sha256=qtHAOo7MvM7atWgxApYXZ0Dmw5zoP45ErPH3mnx9Kvk,2947
|
258
258
|
omlish/inject/impl/multis.py,sha256=rRIWNCiTGaSWQUz_jxEy8LUmzdJDAlG94sLHYDS-ncg,2048
|
259
259
|
omlish/inject/impl/origins.py,sha256=-cdcwz3BWb5LuC9Yn5ynYOwyPsKH06-kCc-3U0PxZ5w,1640
|
260
260
|
omlish/inject/impl/privates.py,sha256=alpCYyk5VJ9lJknbRH2nLVNFYVvFhkj-VC1Vco3zCFQ,2613
|
@@ -298,15 +298,17 @@ omlish/lifecycles/manager.py,sha256=Au66KaO-fI-SEJALaPUJsCHYW2GE20xextk1wKn2BEU,
|
|
298
298
|
omlish/lifecycles/states.py,sha256=zqMOU2ZU-MDNnWuwauM3_anIAiXM8LoBDElDEraptFg,1292
|
299
299
|
omlish/lifecycles/transitions.py,sha256=qQtFby-h4VzbvgaUqT2NnbNumlcOx9FVVADP9t83xj4,1939
|
300
300
|
omlish/lite/__init__.py,sha256=Y3l4WY4JRi2uLG6kgbGp93fuGfkxkKwZDvhsa0Rwgtk,15
|
301
|
-
omlish/lite/cached.py,sha256=
|
301
|
+
omlish/lite/cached.py,sha256=Fs-ljXVJmHBjAaHc-JuJXMEV4MNSX5c_KHZIM3AEaIw,694
|
302
302
|
omlish/lite/check.py,sha256=ouJme9tkzWXKymm_xZDK4mngdYSkxDrok6CSegvf-1w,1015
|
303
|
-
omlish/lite/contextmanagers.py,sha256=
|
303
|
+
omlish/lite/contextmanagers.py,sha256=_jfNdpYvxkbKwyjQLbK-o69W89GoEuUfl_NrCosE9lU,1308
|
304
304
|
omlish/lite/docker.py,sha256=3IVZZtIm7-UdB2SwArmN_MosTva1_KifyYp3YWjODbE,337
|
305
|
+
omlish/lite/inject.py,sha256=O3k8EYRKRKTkqoamM7awbcBvnYwy_fKIUPVf4FcObyg,15060
|
305
306
|
omlish/lite/io.py,sha256=lcpI1cS_Kn90tvYMg8ZWkSlYloS4RFqXCk-rKyclhdg,3148
|
306
307
|
omlish/lite/journald.py,sha256=3nfahFbTrdrfp9txhtto6JYAyrus2kcAFtviqdm3qAo,3949
|
307
308
|
omlish/lite/json.py,sha256=7-02Ny4fq-6YAu5ynvqoijhuYXWpLmfCI19GUeZnb1c,740
|
308
309
|
omlish/lite/logs.py,sha256=tw7mbQslkyo9LopfgQnj0tYiqJ9TDNiw7D07aF7Dm2g,6176
|
309
310
|
omlish/lite/marshal.py,sha256=SyYMsJ-TaGO9FX7LykBB0WtqsqetX9eLBotPiz3M_xg,9478
|
311
|
+
omlish/lite/maybes.py,sha256=7OlHJ8Q2r4wQ-aRbZSlJY7x0e8gDvufFdlohGEIJ3P4,833
|
310
312
|
omlish/lite/pidfile.py,sha256=PRSDOAXmNkNwxh-Vwif0Nrs8RAmWroiNhLKIbdjwzBc,1723
|
311
313
|
omlish/lite/reflect.py,sha256=9QYJwdINraq1JNMEgvoqeSlVvRRgOXpxAkpgX8EgRXc,1307
|
312
314
|
omlish/lite/runtime.py,sha256=VUhmNQvwf8QzkWSKj4Q0ReieJA_PzHaJNRBivfTseow,452
|
@@ -370,16 +372,16 @@ omlish/secrets/secrets.py,sha256=cnDGBoPknVxsCN04_gqcJT_7Ebk3iO3VPkRZ2oMjkMw,786
|
|
370
372
|
omlish/secrets/subprocesses.py,sha256=EcnKlHHtnUMHGrBWXDfu8tv28wlgZx4P4GOiuPW9Vo8,1105
|
371
373
|
omlish/specs/__init__.py,sha256=zZwF8yXTEkSstYtORkDhVLK-_hWU8WOJCuBpognb_NY,118
|
372
374
|
omlish/specs/jmespath/LICENSE,sha256=IH-ZZlZkS8XMkf_ubNVD1aYHQ2l_wd0tmHtXrCcYpRU,1113
|
373
|
-
omlish/specs/jmespath/__init__.py,sha256=
|
375
|
+
omlish/specs/jmespath/__init__.py,sha256=MfBlUXNSPq5pRyboMgBk8JoIj0lQo-2TQ6Re7IwGQK0,2079
|
374
376
|
omlish/specs/jmespath/__main__.py,sha256=wIXm6bs08etNG_GZlN2rBkADPb0rKfL2HSkm8spnpxw,200
|
375
|
-
omlish/specs/jmespath/ast.py,sha256=
|
377
|
+
omlish/specs/jmespath/ast.py,sha256=XhcUGodHIdsY3-hVZEfpeW6LBehRjLbxVFXkMfZhRdk,5386
|
376
378
|
omlish/specs/jmespath/cli.py,sha256=Lw57Eq5rmpwTwsvOzNmce_-XyoM84OIx5cuPgjUXNb0,2197
|
377
379
|
omlish/specs/jmespath/exceptions.py,sha256=Co1HiUBPFNwFgZY3FV_ayuZoSgZIAmDcImImxauYNxc,4435
|
378
|
-
omlish/specs/jmespath/functions.py,sha256=
|
380
|
+
omlish/specs/jmespath/functions.py,sha256=lE_MlW5rDQirDCE9HtcAG-17kuHhH36RaPaQfk97xDY,22595
|
379
381
|
omlish/specs/jmespath/lexer.py,sha256=hlPGCXPzGhd9ySj-z2cGTbyC9z3e0Io78IMYJZSEwNk,12647
|
380
|
-
omlish/specs/jmespath/parser.py,sha256=
|
382
|
+
omlish/specs/jmespath/parser.py,sha256=IPJ0fCv1Aj2MhsDx5XuddtM2LnnLrynuGs4g7PYCmf0,24453
|
381
383
|
omlish/specs/jmespath/scope.py,sha256=UyDsl9rv_c8DCjJBuVIA2ESu1jrgYvuwEKiaJDQKnT0,1590
|
382
|
-
omlish/specs/jmespath/visitor.py,sha256
|
384
|
+
omlish/specs/jmespath/visitor.py,sha256=yneRMO4qf3k2Mdcm2cPC0ozRgOaudzlxRVRGatztJzs,16569
|
383
385
|
omlish/specs/jsonrpc/__init__.py,sha256=E0EogYSKmbj1D-V57tBgPDTyVuD8HosHqVg0Vh1CVwM,416
|
384
386
|
omlish/specs/jsonrpc/errors.py,sha256=-Zgmlo6bV6J8w5f8h9axQgLquIFBHDgIwcpufEH5NsE,707
|
385
387
|
omlish/specs/jsonrpc/marshal.py,sha256=iXZNR7n0vfL_yiPFFYN-ZyGlzknNXExs2qC1HFChGPU,1913
|
@@ -471,9 +473,9 @@ omlish/text/glyphsplit.py,sha256=Ug-dPRO7x-OrNNr8g1y6DotSZ2KH0S-VcOmUobwa4B0,329
|
|
471
473
|
omlish/text/indent.py,sha256=6Jj6TFY9unaPa4xPzrnZemJ-fHsV53IamP93XGjSUHs,1274
|
472
474
|
omlish/text/parts.py,sha256=7vPF1aTZdvLVYJ4EwBZVzRSy8XB3YqPd7JwEnNGGAOo,6495
|
473
475
|
omlish/text/random.py,sha256=jNWpqiaKjKyTdMXC-pWAsSC10AAP-cmRRPVhm59ZWLk,194
|
474
|
-
omlish-0.0.0.
|
475
|
-
omlish-0.0.0.
|
476
|
-
omlish-0.0.0.
|
477
|
-
omlish-0.0.0.
|
478
|
-
omlish-0.0.0.
|
479
|
-
omlish-0.0.0.
|
476
|
+
omlish-0.0.0.dev121.dist-info/LICENSE,sha256=B_hVtavaA8zCYDW99DYdcpDLKz1n3BBRjZrcbv8uG8c,1451
|
477
|
+
omlish-0.0.0.dev121.dist-info/METADATA,sha256=a5C2OhlCjHtn2VNKTUvzGAslZqvU4XAYaOvBfNd1884,4000
|
478
|
+
omlish-0.0.0.dev121.dist-info/WHEEL,sha256=R06PA3UVYHThwHvxuRWMqaGcr-PuniXahwjmQRFMEkY,91
|
479
|
+
omlish-0.0.0.dev121.dist-info/entry_points.txt,sha256=Lt84WvRZJskWCAS7xnQGZIeVWksprtUHj0llrvVmod8,35
|
480
|
+
omlish-0.0.0.dev121.dist-info/top_level.txt,sha256=pePsKdLu7DvtUiecdYXJ78iO80uDNmBlqe-8hOzOmfs,7
|
481
|
+
omlish-0.0.0.dev121.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|