omlish 0.0.0.dev484__py3-none-any.whl → 0.0.0.dev506__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/CODESTYLE.md +345 -0
- omlish/README.md +199 -0
- omlish/__about__.py +12 -5
- omlish/_check.cc +209 -0
- omlish/check.py +11 -0
- omlish/dataclasses/__init__.py +4 -0
- omlish/dataclasses/impl/concerns/frozen.py +4 -1
- omlish/dataclasses/impl/generation/plans.py +2 -17
- omlish/dataclasses/impl/generation/processor.py +2 -2
- omlish/dataclasses/impl/processing/driving.py +13 -1
- omlish/dataclasses/tools/replace.py +27 -0
- omlish/diag/_pycharm/runhack.py +1 -1
- omlish/dispatch/functions.py +1 -1
- omlish/formats/json/stream/lexing.py +13 -5
- omlish/formats/json/stream/parsing.py +1 -1
- omlish/inject/README.md +430 -0
- omlish/inject/__init__.py +20 -11
- omlish/inject/_dataclasses.py +1545 -1383
- omlish/inject/binder.py +7 -4
- omlish/inject/eagers.py +2 -4
- omlish/inject/elements.py +4 -0
- omlish/inject/helpers/late.py +76 -0
- omlish/inject/{managed.py → helpers/managed.py} +37 -34
- omlish/inject/impl/elements.py +7 -4
- omlish/inject/impl/injector.py +14 -26
- omlish/inject/impl/inspect.py +0 -8
- omlish/inject/impl/origins.py +1 -0
- omlish/inject/impl/privates.py +2 -6
- omlish/inject/impl/providers.py +0 -4
- omlish/inject/impl/scopes.py +14 -18
- omlish/inject/inspect.py +10 -1
- omlish/inject/multis.py +0 -3
- omlish/inject/scopes.py +7 -5
- omlish/io/buffers.py +35 -8
- omlish/lang/__init__.py +10 -0
- omlish/lang/classes/simple.py +2 -1
- omlish/lang/iterables.py +6 -0
- omlish/lang/objects.py +13 -0
- omlish/lang/outcomes.py +1 -1
- omlish/lang/recursion.py +1 -1
- omlish/lang/sequences.py +33 -0
- omlish/lifecycles/README.md +30 -0
- omlish/lifecycles/__init__.py +87 -13
- omlish/lifecycles/_dataclasses.py +1388 -0
- omlish/lifecycles/base.py +178 -64
- omlish/lifecycles/contextmanagers.py +113 -4
- omlish/lifecycles/controller.py +150 -87
- omlish/lifecycles/injection.py +143 -0
- omlish/lifecycles/listeners.py +56 -0
- omlish/lifecycles/managed.py +142 -0
- omlish/lifecycles/manager.py +218 -93
- omlish/lifecycles/states.py +2 -0
- omlish/lifecycles/transitions.py +3 -0
- omlish/lifecycles/unwrap.py +57 -0
- omlish/lite/maybes.py +7 -0
- omlish/lite/typing.py +33 -0
- omlish/logs/_amalg.py +1 -1
- omlish/logs/all.py +36 -11
- omlish/logs/asyncs.py +73 -0
- omlish/logs/base.py +101 -12
- omlish/logs/bisync.py +99 -0
- omlish/logs/contexts.py +4 -1
- omlish/logs/lists.py +125 -0
- omlish/logs/modules.py +19 -1
- omlish/logs/std/loggers.py +6 -1
- omlish/logs/std/noisy.py +11 -9
- omlish/logs/{standard.py → std/standard.py} +3 -4
- omlish/logs/utils.py +16 -1
- omlish/marshal/_dataclasses.py +813 -813
- omlish/reflect/__init__.py +43 -26
- omlish/reflect/ops.py +10 -1
- omlish/specs/jmespath/_dataclasses.py +597 -597
- omlish/specs/jsonschema/keywords/_dataclasses.py +244 -244
- omlish/sql/__init__.py +24 -5
- omlish/sql/api/dbapi.py +1 -1
- omlish/sql/dbapi/__init__.py +15 -0
- omlish/sql/{dbapi.py → dbapi/drivers.py} +2 -2
- omlish/sql/queries/__init__.py +3 -0
- omlish/testing/pytest/plugins/asyncs/plugin.py +2 -0
- omlish/text/docwrap/cli.py +5 -0
- omlish/typedvalues/_collection.cc +500 -0
- omlish/typedvalues/collection.py +159 -62
- omlish/typedvalues/generic.py +5 -4
- omlish/typedvalues/values.py +6 -0
- {omlish-0.0.0.dev484.dist-info → omlish-0.0.0.dev506.dist-info}/METADATA +14 -9
- {omlish-0.0.0.dev484.dist-info → omlish-0.0.0.dev506.dist-info}/RECORD +92 -77
- omlish/lifecycles/abstract.py +0 -86
- /omlish/inject/{impl → helpers}/proxy.py +0 -0
- /omlish/sql/{abc.py → dbapi/abc.py} +0 -0
- {omlish-0.0.0.dev484.dist-info → omlish-0.0.0.dev506.dist-info}/WHEEL +0 -0
- {omlish-0.0.0.dev484.dist-info → omlish-0.0.0.dev506.dist-info}/entry_points.txt +0 -0
- {omlish-0.0.0.dev484.dist-info → omlish-0.0.0.dev506.dist-info}/licenses/LICENSE +0 -0
- {omlish-0.0.0.dev484.dist-info → omlish-0.0.0.dev506.dist-info}/top_level.txt +0 -0
omlish/inject/binder.py
CHANGED
|
@@ -88,7 +88,7 @@ def bind(
|
|
|
88
88
|
in_: Scope | None = None,
|
|
89
89
|
singleton: bool = False,
|
|
90
90
|
|
|
91
|
-
eager: bool = False,
|
|
91
|
+
eager: bool | int = False,
|
|
92
92
|
expose: bool = False,
|
|
93
93
|
) -> Element | Elements:
|
|
94
94
|
if obj is None or obj is inspect.Parameter.empty:
|
|
@@ -117,7 +117,10 @@ def bind(
|
|
|
117
117
|
elif _is_fn(obj) and not has_to:
|
|
118
118
|
sig = _inspect.signature(obj)
|
|
119
119
|
ty = rfl.type_(sig.return_annotation)
|
|
120
|
-
|
|
120
|
+
if inspect.iscoroutinefunction(obj):
|
|
121
|
+
to_async_fn = obj
|
|
122
|
+
else:
|
|
123
|
+
to_fn = obj
|
|
121
124
|
key = Key(ty)
|
|
122
125
|
else:
|
|
123
126
|
if to_const is not None:
|
|
@@ -180,8 +183,8 @@ def bind(
|
|
|
180
183
|
|
|
181
184
|
elements: list[Element] = [binding]
|
|
182
185
|
|
|
183
|
-
if eager:
|
|
184
|
-
elements.append(Eager(key))
|
|
186
|
+
if eager is not False:
|
|
187
|
+
elements.append(Eager(key, priority=eager if isinstance(eager, int) else 0))
|
|
185
188
|
if expose:
|
|
186
189
|
elements.append(Expose(key))
|
|
187
190
|
|
omlish/inject/eagers.py
CHANGED
|
@@ -1,7 +1,3 @@
|
|
|
1
|
-
"""
|
|
2
|
-
TODO:
|
|
3
|
-
- SCOPED - eagers for EACH SCOPE
|
|
4
|
-
"""
|
|
5
1
|
from .. import check
|
|
6
2
|
from .. import dataclasses as dc
|
|
7
3
|
from .. import lang
|
|
@@ -16,3 +12,5 @@ from .keys import Key
|
|
|
16
12
|
@dc.extra_class_params(cache_hash=True)
|
|
17
13
|
class Eager(Element, lang.Final):
|
|
18
14
|
key: Key = dc.xfield(coerce=check.of_isinstance(Key))
|
|
15
|
+
|
|
16
|
+
priority: int = dc.xfield(0, kw_only=True)
|
omlish/inject/elements.py
CHANGED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
"""
|
|
2
|
+
A minor tidiness for hiding refs to [Async]Injector in circ-dep workarounds. Unfortunately unsuitable outside of
|
|
3
|
+
injection modules due to it itself being in here (as user code shouldn't reference injector guts), but at least it's
|
|
4
|
+
something.
|
|
5
|
+
"""
|
|
6
|
+
import abc
|
|
7
|
+
import functools
|
|
8
|
+
import typing as ta
|
|
9
|
+
|
|
10
|
+
from ... import lang
|
|
11
|
+
from ... import reflect as rfl
|
|
12
|
+
from ..binder import bind
|
|
13
|
+
from ..elements import Elements
|
|
14
|
+
from ..elements import as_elements
|
|
15
|
+
from ..injector import AsyncInjector
|
|
16
|
+
from ..inspect import KwargsTarget
|
|
17
|
+
from ..keys import Key
|
|
18
|
+
from ..keys import as_key
|
|
19
|
+
from ..sync import Injector
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
T = ta.TypeVar('T')
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
##
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class Late(lang.Abstract, ta.Generic[T]):
|
|
29
|
+
@abc.abstractmethod
|
|
30
|
+
def __call__(self) -> T:
|
|
31
|
+
raise NotImplementedError
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class AsyncLate(lang.Abstract, ta.Generic[T]):
|
|
35
|
+
@abc.abstractmethod
|
|
36
|
+
def __call__(self) -> ta.Awaitable[T]:
|
|
37
|
+
raise NotImplementedError
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
#
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def _bind_late(
|
|
44
|
+
injector_cls: type,
|
|
45
|
+
late_cls: ta.Any,
|
|
46
|
+
inner: ta.Any,
|
|
47
|
+
outer: ta.Any | None = None,
|
|
48
|
+
) -> Elements:
|
|
49
|
+
inner_key = as_key(inner)
|
|
50
|
+
|
|
51
|
+
outer_key: Key
|
|
52
|
+
outer_fac: ta.Callable[[ta.Any], ta.Any]
|
|
53
|
+
if outer is None:
|
|
54
|
+
inner_ann = rfl.to_annotation(inner_key.ty)
|
|
55
|
+
outer_ann = late_cls[inner_ann]
|
|
56
|
+
outer_key = Key(rfl.type_(outer_ann), tag=inner_key.tag)
|
|
57
|
+
outer_fac = lang.identity
|
|
58
|
+
else:
|
|
59
|
+
outer_key = as_key(outer)
|
|
60
|
+
outer_cls = rfl.get_concrete_type(outer_key.ty)
|
|
61
|
+
outer_fac = outer_cls # type: ignore[assignment]
|
|
62
|
+
|
|
63
|
+
return as_elements(
|
|
64
|
+
bind(outer_key, to_fn=KwargsTarget.of( # noqa
|
|
65
|
+
lambda i: outer_fac(functools.partial(i.provide, inner_key)),
|
|
66
|
+
i=injector_cls,
|
|
67
|
+
)),
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def bind_late(inner: ta.Any, outer: ta.Any | None = None) -> Elements:
|
|
72
|
+
return _bind_late(Injector, Late, inner, outer)
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def bind_async_late(inner: ta.Any, outer: ta.Any | None = None) -> Elements:
|
|
76
|
+
return _bind_late(AsyncInjector, AsyncLate, inner, outer)
|
|
@@ -5,20 +5,20 @@ TODO:
|
|
|
5
5
|
import contextlib
|
|
6
6
|
import typing as ta
|
|
7
7
|
|
|
8
|
-
from
|
|
9
|
-
from
|
|
10
|
-
from
|
|
11
|
-
from
|
|
8
|
+
from ... import lang
|
|
9
|
+
from ..binder import bind
|
|
10
|
+
from ..elements import Elemental
|
|
11
|
+
from ..impl.inspect import build_kwargs_target
|
|
12
12
|
|
|
13
13
|
|
|
14
14
|
if ta.TYPE_CHECKING:
|
|
15
|
-
from
|
|
16
|
-
from
|
|
17
|
-
from
|
|
15
|
+
from .. import injector as _injector
|
|
16
|
+
from .. import maysync as _maysync
|
|
17
|
+
from .. import sync as _sync
|
|
18
18
|
else:
|
|
19
|
-
_injector = lang.proxy_import('
|
|
20
|
-
_maysync = lang.proxy_import('
|
|
21
|
-
_sync = lang.proxy_import('
|
|
19
|
+
_injector = lang.proxy_import('..injector', __package__)
|
|
20
|
+
_maysync = lang.proxy_import('..maysync', __package__)
|
|
21
|
+
_sync = lang.proxy_import('..sync', __package__)
|
|
22
22
|
|
|
23
23
|
|
|
24
24
|
T = ta.TypeVar('T')
|
|
@@ -27,14 +27,15 @@ T = ta.TypeVar('T')
|
|
|
27
27
|
##
|
|
28
28
|
|
|
29
29
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
30
|
+
def create_async_managed_injector(*args: Elemental) -> ta.AsyncContextManager['_injector.AsyncInjector']:
|
|
31
|
+
@contextlib.asynccontextmanager
|
|
32
|
+
async def inner():
|
|
33
|
+
async with contextlib.AsyncExitStack() as aes:
|
|
34
|
+
yield await _injector.create_async_injector(
|
|
35
|
+
bind(contextlib.AsyncExitStack, to_const=aes),
|
|
36
|
+
*args,
|
|
37
|
+
)
|
|
38
|
+
return inner()
|
|
38
39
|
|
|
39
40
|
|
|
40
41
|
def make_async_managed_provider(
|
|
@@ -61,14 +62,15 @@ def make_async_managed_provider(
|
|
|
61
62
|
##
|
|
62
63
|
|
|
63
64
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
65
|
+
def create_managed_injector(*args: Elemental) -> ta.ContextManager['_sync.Injector']:
|
|
66
|
+
@contextlib.contextmanager
|
|
67
|
+
def inner():
|
|
68
|
+
with contextlib.ExitStack() as es:
|
|
69
|
+
yield _sync.create_injector(
|
|
70
|
+
bind(contextlib.ExitStack, to_const=es),
|
|
71
|
+
*args,
|
|
72
|
+
)
|
|
73
|
+
return inner()
|
|
72
74
|
|
|
73
75
|
|
|
74
76
|
def make_managed_provider(
|
|
@@ -95,14 +97,15 @@ def make_managed_provider(
|
|
|
95
97
|
##
|
|
96
98
|
|
|
97
99
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
100
|
+
def create_maysync_managed_injector(*args: Elemental) -> ta.ContextManager['_maysync.MaysyncInjector']:
|
|
101
|
+
@contextlib.contextmanager
|
|
102
|
+
def inner():
|
|
103
|
+
with contextlib.ExitStack() as es:
|
|
104
|
+
yield _maysync.create_maysync_injector(
|
|
105
|
+
bind(contextlib.ExitStack, to_const=es),
|
|
106
|
+
*args,
|
|
107
|
+
)
|
|
108
|
+
return inner()
|
|
106
109
|
|
|
107
110
|
|
|
108
111
|
def make_maysync_managed_provider(
|
omlish/inject/impl/elements.py
CHANGED
|
@@ -214,13 +214,16 @@ class ElementCollection(CollectedElements, lang.Final):
|
|
|
214
214
|
return [sb.scope for sb in self.elements_of_type(ScopeBinding)]
|
|
215
215
|
|
|
216
216
|
@lang.cached_function
|
|
217
|
-
def
|
|
217
|
+
def sorted_eager_keys_by_scope(self) -> ta.Mapping[Scope, ta.Sequence[Key]]:
|
|
218
218
|
bim = self.binding_impl_map()
|
|
219
|
-
|
|
219
|
+
dct: dict[Scope, list[Eager]] = {}
|
|
220
220
|
for e in self.elements_of_type(Eager):
|
|
221
221
|
bi = bim[e.key]
|
|
222
|
-
|
|
223
|
-
return
|
|
222
|
+
dct.setdefault(bi.scope, []).append(e)
|
|
223
|
+
return {
|
|
224
|
+
sc: tuple(eg.key for eg in sorted(egs, key=lambda eg: eg.priority))
|
|
225
|
+
for sc, egs in dct.items()
|
|
226
|
+
}
|
|
224
227
|
|
|
225
228
|
|
|
226
229
|
##
|
omlish/inject/impl/injector.py
CHANGED
|
@@ -1,18 +1,3 @@
|
|
|
1
|
-
"""
|
|
2
|
-
TODO:
|
|
3
|
-
- ** can currently bind in a child/private scope shadowing an external parent binding **
|
|
4
|
-
- better source tracking
|
|
5
|
-
- scope bindings, auto in root
|
|
6
|
-
- injector-internal / blacklisted bindings (Injector itself, default scopes) without rebuilding ElementCollection
|
|
7
|
-
- config - proxies, impl select, etc
|
|
8
|
-
- config is probably shared with ElementCollection... but not 'bound', must be shared everywhere
|
|
9
|
-
- InjectorRoot object?
|
|
10
|
-
- ** eagers in any scope, on scope init/open
|
|
11
|
-
- unions - raise on ambiguous - usecase: sql.AsyncEngineLike
|
|
12
|
-
- multiple live request scopes on single injector - use private injectors?
|
|
13
|
-
- more listeners - UnboundKeyListener
|
|
14
|
-
- lazy parent listener chain cache thing
|
|
15
|
-
"""
|
|
16
1
|
import contextlib
|
|
17
2
|
import functools
|
|
18
3
|
import itertools
|
|
@@ -73,14 +58,14 @@ class AsyncInjectorImpl(AsyncInjector, lang.Final):
|
|
|
73
58
|
|
|
74
59
|
self._bim = ec.binding_impl_map()
|
|
75
60
|
|
|
76
|
-
self._ekbs = ec.
|
|
61
|
+
self._ekbs = ec.sorted_eager_keys_by_scope()
|
|
77
62
|
|
|
78
|
-
self._pls: tuple[ProvisionListener, ...] =
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
ec.elements_of_type(ProvisionListenerBinding)
|
|
82
|
-
|
|
83
|
-
)
|
|
63
|
+
self._pls: tuple[ProvisionListener, ...] = (
|
|
64
|
+
*(
|
|
65
|
+
b.listener
|
|
66
|
+
for b in ec.elements_of_type(ProvisionListenerBinding)
|
|
67
|
+
),
|
|
68
|
+
*(p._pls if p is not None else []), # noqa
|
|
84
69
|
)
|
|
85
70
|
|
|
86
71
|
self._root: AsyncInjectorImpl = p._root if p is not None else self # noqa
|
|
@@ -93,6 +78,9 @@ class AsyncInjectorImpl(AsyncInjector, lang.Final):
|
|
|
93
78
|
)
|
|
94
79
|
}
|
|
95
80
|
|
|
81
|
+
if self._p is not None:
|
|
82
|
+
self._p._add_child(self) # noqa
|
|
83
|
+
|
|
96
84
|
_cs: weakref.WeakSet['AsyncInjectorImpl'] | None = None # noqa
|
|
97
85
|
|
|
98
86
|
__cur_req: ta.Optional['AsyncInjectorImpl._Request'] = None
|
|
@@ -123,8 +111,8 @@ class AsyncInjectorImpl(AsyncInjector, lang.Final):
|
|
|
123
111
|
def get_scope_impl(self, sc: Scope) -> ScopeImpl:
|
|
124
112
|
return self._scopes[sc]
|
|
125
113
|
|
|
126
|
-
def
|
|
127
|
-
c
|
|
114
|
+
def _add_child(self, c: 'AsyncInjectorImpl') -> AsyncInjector:
|
|
115
|
+
check.isinstance(c, AsyncInjectorImpl)
|
|
128
116
|
if self._cs is None:
|
|
129
117
|
self._cs = weakref.WeakSet()
|
|
130
118
|
self._cs.add(c)
|
|
@@ -257,7 +245,7 @@ class AsyncInjectorImpl(AsyncInjector, lang.Final):
|
|
|
257
245
|
return obj(**kws)
|
|
258
246
|
|
|
259
247
|
|
|
260
|
-
async def create_async_injector(ce: CollectedElements) -> AsyncInjector:
|
|
261
|
-
i = AsyncInjectorImpl(ce)
|
|
248
|
+
async def create_async_injector(ce: CollectedElements, p: AsyncInjector | None = None) -> AsyncInjector:
|
|
249
|
+
i = AsyncInjectorImpl(ce, check.isinstance(p, (AsyncInjectorImpl, None)))
|
|
262
250
|
await i._init() # noqa
|
|
263
251
|
return i
|
omlish/inject/impl/inspect.py
CHANGED
omlish/inject/impl/origins.py
CHANGED
omlish/inject/impl/privates.py
CHANGED
|
@@ -1,12 +1,7 @@
|
|
|
1
|
-
"""
|
|
2
|
-
TODO:
|
|
3
|
-
- add origin to Id
|
|
4
|
-
"""
|
|
5
1
|
import itertools
|
|
6
2
|
import typing as ta
|
|
7
3
|
|
|
8
4
|
from ... import cached
|
|
9
|
-
from ... import check
|
|
10
5
|
from ... import dataclasses as dc
|
|
11
6
|
from ... import lang
|
|
12
7
|
from ..bindings import Binding
|
|
@@ -20,6 +15,7 @@ from ..providers import Provider
|
|
|
20
15
|
from ..scopes import Singleton
|
|
21
16
|
from .elements import ElementCollection
|
|
22
17
|
from .injector import AsyncInjectorImpl
|
|
18
|
+
from .injector import create_async_injector
|
|
23
19
|
from .providers import InternalProvider
|
|
24
20
|
from .providers import ProviderImpl
|
|
25
21
|
|
|
@@ -48,7 +44,7 @@ class PrivateInjectorProviderImpl(ProviderImpl, lang.Final):
|
|
|
48
44
|
return ()
|
|
49
45
|
|
|
50
46
|
async def provide(self, injector: AsyncInjector) -> ta.Any:
|
|
51
|
-
return
|
|
47
|
+
return await create_async_injector(self.ec, injector)
|
|
52
48
|
|
|
53
49
|
|
|
54
50
|
##
|
omlish/inject/impl/providers.py
CHANGED
omlish/inject/impl/scopes.py
CHANGED
|
@@ -1,9 +1,3 @@
|
|
|
1
|
-
"""
|
|
2
|
-
TODO:
|
|
3
|
-
- ContextVar ('context')
|
|
4
|
-
- greenlet?
|
|
5
|
-
- dynamic? https://github.com/wrmsr/iceworm/blob/2f6b4d5e9d237ef9665f7d57cfa6ce328efa0757/iceworm/utils/inject.py#L44
|
|
6
|
-
"""
|
|
7
1
|
import abc
|
|
8
2
|
import contextlib
|
|
9
3
|
import threading
|
|
@@ -154,18 +148,20 @@ class SeededScopeImpl(ScopeImpl):
|
|
|
154
148
|
self._ii = check.isinstance(i, _injector.AsyncInjectorImpl)
|
|
155
149
|
self._ssi = check.isinstance(self._ii.get_scope_impl(self._ss), SeededScopeImpl)
|
|
156
150
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
151
|
+
def __call__(self, seeds: ta.Mapping[Key, ta.Any]) -> ta.AsyncContextManager[None]:
|
|
152
|
+
@contextlib.asynccontextmanager
|
|
153
|
+
async def inner():
|
|
154
|
+
try:
|
|
155
|
+
if self._ssi._st is not None: # noqa
|
|
156
|
+
raise ScopeAlreadyOpenError(self._ss)
|
|
157
|
+
self._ssi._st = SeededScopeImpl.State(dict(seeds)) # noqa
|
|
158
|
+
await self._ii._instantiate_eagers(self._ss) # noqa
|
|
159
|
+
yield
|
|
160
|
+
finally:
|
|
161
|
+
if self._ssi._st is None: # noqa
|
|
162
|
+
raise ScopeNotOpenError(self._ss)
|
|
163
|
+
self._ssi._st = None # noqa
|
|
164
|
+
return inner()
|
|
169
165
|
|
|
170
166
|
def auto_elements(self) -> Elements:
|
|
171
167
|
return as_elements(
|
omlish/inject/inspect.py
CHANGED
|
@@ -58,7 +58,7 @@ class KwargsTarget(ta.NamedTuple):
|
|
|
58
58
|
|
|
59
59
|
return cls(
|
|
60
60
|
obj,
|
|
61
|
-
|
|
61
|
+
(*kws, *kw_kwargs),
|
|
62
62
|
)
|
|
63
63
|
|
|
64
64
|
|
|
@@ -68,3 +68,12 @@ def tag(obj: T, **kwargs: ta.Any) -> T:
|
|
|
68
68
|
|
|
69
69
|
def build_kwargs_target(obj: ta.Any, **kwargs: ta.Any) -> KwargsTarget:
|
|
70
70
|
return _inspect.build_kwargs_target(obj, **kwargs)
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
##
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def target(**kwargs: ta.Any) -> ta.Callable[[ta.Any], KwargsTarget]:
|
|
77
|
+
def inner(obj: ta.Any) -> KwargsTarget:
|
|
78
|
+
return KwargsTarget.of(obj, **kwargs)
|
|
79
|
+
return inner
|
omlish/inject/multis.py
CHANGED
omlish/inject/scopes.py
CHANGED
|
@@ -89,14 +89,16 @@ def bind_scope_seed(k: ta.Any, ss: SeededScope) -> Element:
|
|
|
89
89
|
##
|
|
90
90
|
|
|
91
91
|
|
|
92
|
-
|
|
93
|
-
async def async_enter_seeded_scope(
|
|
92
|
+
def async_enter_seeded_scope(
|
|
94
93
|
i: '_injector.AsyncInjector',
|
|
95
94
|
ss: SeededScope,
|
|
96
95
|
keys: ta.Mapping[Key, ta.Any],
|
|
97
|
-
) -> ta.
|
|
98
|
-
|
|
99
|
-
|
|
96
|
+
) -> ta.AsyncContextManager[None]:
|
|
97
|
+
@contextlib.asynccontextmanager
|
|
98
|
+
async def inner():
|
|
99
|
+
async with (await i.provide(Key(SeededScope.Manager, tag=ss)))(keys):
|
|
100
|
+
yield
|
|
101
|
+
return inner()
|
|
100
102
|
|
|
101
103
|
|
|
102
104
|
def enter_seeded_scope(
|
omlish/io/buffers.py
CHANGED
|
@@ -190,16 +190,18 @@ class ReadableListBuffer:
|
|
|
190
190
|
super().__init__()
|
|
191
191
|
|
|
192
192
|
self._lst: list[bytes] = []
|
|
193
|
+
self._len = 0
|
|
193
194
|
|
|
194
195
|
def __bool__(self) -> ta.NoReturn:
|
|
195
196
|
raise TypeError("Use 'buf is not None' or 'len(buf)'.")
|
|
196
197
|
|
|
197
198
|
def __len__(self) -> int:
|
|
198
|
-
return
|
|
199
|
+
return self._len
|
|
199
200
|
|
|
200
201
|
def feed(self, d: bytes) -> None:
|
|
201
202
|
if d:
|
|
202
203
|
self._lst.append(d)
|
|
204
|
+
self._len += len(d)
|
|
203
205
|
|
|
204
206
|
def _chop(self, i: int, e: int) -> bytes:
|
|
205
207
|
lst = self._lst
|
|
@@ -215,6 +217,8 @@ class ReadableListBuffer:
|
|
|
215
217
|
*lst[i + 1:],
|
|
216
218
|
]
|
|
217
219
|
|
|
220
|
+
self._len -= len(o)
|
|
221
|
+
|
|
218
222
|
return o
|
|
219
223
|
|
|
220
224
|
def read(self, n: ta.Optional[int] = None) -> ta.Optional[bytes]:
|
|
@@ -224,6 +228,7 @@ class ReadableListBuffer:
|
|
|
224
228
|
|
|
225
229
|
o = b''.join(self._lst)
|
|
226
230
|
self._lst = []
|
|
231
|
+
self._len = 0
|
|
227
232
|
return o
|
|
228
233
|
|
|
229
234
|
if not (lst := self._lst):
|
|
@@ -293,7 +298,12 @@ class ReadableListBuffer:
|
|
|
293
298
|
if not (b := self._raw.read1(n)):
|
|
294
299
|
break
|
|
295
300
|
self._buf.feed(b)
|
|
296
|
-
|
|
301
|
+
|
|
302
|
+
if len(self._buf) >= n:
|
|
303
|
+
return self._buf.read(n) or b''
|
|
304
|
+
|
|
305
|
+
# EOF with a partial buffer: return what we have.
|
|
306
|
+
return self._buf.read() or b''
|
|
297
307
|
|
|
298
308
|
def readall(self) -> bytes:
|
|
299
309
|
buf = io.BytesIO()
|
|
@@ -343,7 +353,12 @@ class ReadableListBuffer:
|
|
|
343
353
|
if not (b := await self._raw.read1(n)):
|
|
344
354
|
break
|
|
345
355
|
self._buf.feed(b)
|
|
346
|
-
|
|
356
|
+
|
|
357
|
+
if len(self._buf) >= n:
|
|
358
|
+
return self._buf.read(n) or b''
|
|
359
|
+
|
|
360
|
+
# EOF with a partial buffer: return what we have.
|
|
361
|
+
return self._buf.read() or b''
|
|
347
362
|
|
|
348
363
|
async def readall(self) -> bytes:
|
|
349
364
|
buf = io.BytesIO()
|
|
@@ -396,16 +411,28 @@ class IncrementalWriteBuffer:
|
|
|
396
411
|
|
|
397
412
|
t = 0
|
|
398
413
|
for i, d in enumerate(lst): # noqa
|
|
399
|
-
|
|
414
|
+
d = check.not_empty(d)
|
|
415
|
+
n = fn(d)
|
|
400
416
|
if not n:
|
|
401
417
|
break
|
|
418
|
+
|
|
419
|
+
if n > len(d):
|
|
420
|
+
raise ValueError(n)
|
|
421
|
+
|
|
402
422
|
t += n
|
|
403
423
|
|
|
424
|
+
if n < len(d):
|
|
425
|
+
# Short write - keep the remainder of this chunk and stop.
|
|
426
|
+
self._lst = [
|
|
427
|
+
d[n:],
|
|
428
|
+
*lst[i + 1:],
|
|
429
|
+
]
|
|
430
|
+
self._pos += t
|
|
431
|
+
return t
|
|
432
|
+
|
|
404
433
|
if t:
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
*lst[i + 1:],
|
|
408
|
-
]
|
|
434
|
+
# Only fully-written chunks were consumed.
|
|
435
|
+
self._lst = lst[i + 1:]
|
|
409
436
|
self._pos += t
|
|
410
437
|
|
|
411
438
|
return t
|
omlish/lang/__init__.py
CHANGED
|
@@ -341,6 +341,7 @@ with _auto_proxy_init(globals(), update_exports=True):
|
|
|
341
341
|
ilen,
|
|
342
342
|
take,
|
|
343
343
|
consume,
|
|
344
|
+
opt_list,
|
|
344
345
|
peek,
|
|
345
346
|
chunk,
|
|
346
347
|
interleave,
|
|
@@ -381,6 +382,8 @@ with _auto_proxy_init(globals(), update_exports=True):
|
|
|
381
382
|
from .objects import ( # noqa
|
|
382
383
|
arg_repr,
|
|
383
384
|
opt_repr,
|
|
385
|
+
just_repr,
|
|
386
|
+
opt_or_just_repr,
|
|
384
387
|
|
|
385
388
|
can_weakref,
|
|
386
389
|
|
|
@@ -466,6 +469,10 @@ with _auto_proxy_init(globals(), update_exports=True):
|
|
|
466
469
|
iterslice,
|
|
467
470
|
iterrange,
|
|
468
471
|
|
|
472
|
+
seqs_all,
|
|
473
|
+
seqs_equal,
|
|
474
|
+
seqs_identical,
|
|
475
|
+
|
|
469
476
|
SeqView,
|
|
470
477
|
)
|
|
471
478
|
|
|
@@ -621,6 +628,9 @@ with _auto_proxy_init(globals(), update_exports=True):
|
|
|
621
628
|
Func2,
|
|
622
629
|
Func3,
|
|
623
630
|
|
|
631
|
+
CachedFunc0,
|
|
632
|
+
AsyncCachedFunc0,
|
|
633
|
+
|
|
624
634
|
typing_annotations_attr,
|
|
625
635
|
)
|
|
626
636
|
|
omlish/lang/classes/simple.py
CHANGED
|
@@ -3,6 +3,7 @@ import functools
|
|
|
3
3
|
import threading
|
|
4
4
|
import typing as ta
|
|
5
5
|
|
|
6
|
+
from ...lite.abstract import Abstract
|
|
6
7
|
from .restrict import Final
|
|
7
8
|
from .restrict import NotInstantiable
|
|
8
9
|
|
|
@@ -40,7 +41,7 @@ class _MarkerMeta(abc.ABCMeta):
|
|
|
40
41
|
else:
|
|
41
42
|
if set(namespace) - _MARKER_NAMESPACE_KEYS:
|
|
42
43
|
raise TypeError('Markers must not include contents. Did you mean to use Namespace?')
|
|
43
|
-
if Final not in bases:
|
|
44
|
+
if Final not in bases and Abstract not in bases:
|
|
44
45
|
bases += (Final,)
|
|
45
46
|
|
|
46
47
|
return super().__new__(mcls, name, bases, namespace)
|
omlish/lang/iterables.py
CHANGED
|
@@ -26,6 +26,12 @@ def consume(it: ta.Iterable[ta.Any]) -> None:
|
|
|
26
26
|
collections.deque(it, maxlen=0)
|
|
27
27
|
|
|
28
28
|
|
|
29
|
+
def opt_list(it: ta.Iterable[T] | None) -> list[T] | None:
|
|
30
|
+
if it is None:
|
|
31
|
+
return None
|
|
32
|
+
return list(it)
|
|
33
|
+
|
|
34
|
+
|
|
29
35
|
def peek(vs: ta.Iterable[T]) -> tuple[T, ta.Iterator[T]]:
|
|
30
36
|
it = iter(vs)
|
|
31
37
|
v = next(it)
|