omlish 0.0.0.dev447__py3-none-any.whl → 0.0.0.dev493__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/.omlish-manifests.json +12 -0
- omlish/README.md +199 -0
- omlish/__about__.py +21 -16
- omlish/argparse/all.py +17 -9
- omlish/argparse/cli.py +16 -3
- omlish/argparse/utils.py +21 -0
- omlish/asyncs/asyncio/rlock.py +110 -0
- omlish/asyncs/asyncio/sync.py +43 -0
- omlish/asyncs/asyncio/utils.py +2 -0
- omlish/asyncs/sync.py +25 -0
- omlish/bootstrap/_marshal.py +1 -1
- omlish/bootstrap/diag.py +12 -21
- omlish/bootstrap/main.py +2 -5
- omlish/bootstrap/sys.py +27 -28
- omlish/cexts/__init__.py +0 -0
- omlish/cexts/include/omlish/omlish.hh +1 -0
- omlish/collections/__init__.py +13 -1
- omlish/collections/attrregistry.py +210 -0
- omlish/collections/cache/impl.py +1 -0
- omlish/collections/identity.py +1 -0
- omlish/collections/mappings.py +28 -0
- omlish/collections/trie.py +5 -1
- omlish/collections/utils.py +77 -0
- omlish/concurrent/all.py +2 -1
- omlish/concurrent/futures.py +25 -0
- omlish/concurrent/threadlets.py +1 -1
- omlish/daemons/reparent.py +2 -3
- omlish/daemons/spawning.py +2 -3
- omlish/dataclasses/__init__.py +2 -0
- omlish/dataclasses/impl/api/classes/decorator.py +3 -0
- omlish/dataclasses/impl/api/classes/make.py +3 -0
- omlish/dataclasses/impl/concerns/repr.py +15 -2
- omlish/dataclasses/impl/configs.py +97 -37
- omlish/dataclasses/impl/generation/compilation.py +21 -19
- omlish/dataclasses/impl/generation/globals.py +1 -0
- omlish/dataclasses/impl/generation/ops.py +1 -0
- omlish/dataclasses/impl/generation/plans.py +2 -17
- omlish/dataclasses/impl/generation/processor.py +106 -25
- omlish/dataclasses/impl/processing/base.py +8 -0
- omlish/dataclasses/impl/processing/driving.py +19 -7
- omlish/dataclasses/specs.py +1 -0
- omlish/dataclasses/tools/modifiers.py +5 -0
- omlish/diag/_pycharm/runhack.py +1 -1
- omlish/diag/cmds/__init__.py +0 -0
- omlish/diag/{lslocks.py → cmds/lslocks.py} +6 -6
- omlish/diag/{lsof.py → cmds/lsof.py} +6 -6
- omlish/diag/{ps.py → cmds/ps.py} +6 -6
- omlish/diag/pycharm.py +16 -2
- omlish/diag/pydevd.py +58 -40
- omlish/diag/replserver/console.py +1 -1
- omlish/dispatch/__init__.py +18 -12
- omlish/dispatch/methods.py +50 -140
- omlish/dom/rendering.py +1 -1
- omlish/formats/dotenv.py +1 -1
- omlish/formats/json/stream/__init__.py +13 -0
- omlish/funcs/guard.py +225 -0
- omlish/graphs/dot/rendering.py +1 -1
- omlish/http/all.py +44 -4
- omlish/http/clients/asyncs.py +33 -27
- omlish/http/clients/base.py +17 -1
- omlish/http/clients/coro/__init__.py +0 -0
- omlish/http/clients/coro/sync.py +171 -0
- omlish/http/clients/default.py +208 -29
- omlish/http/clients/executor.py +56 -0
- omlish/http/clients/httpx.py +72 -11
- omlish/http/clients/middleware.py +181 -0
- omlish/http/clients/sync.py +33 -27
- omlish/http/clients/syncasync.py +49 -0
- omlish/http/clients/urllib.py +6 -3
- omlish/http/coro/client/connection.py +15 -6
- omlish/http/coro/io.py +2 -0
- omlish/http/flasky/__init__.py +40 -0
- omlish/http/flasky/_compat.py +2 -0
- omlish/http/flasky/api.py +82 -0
- omlish/http/flasky/app.py +203 -0
- omlish/http/flasky/cvs.py +59 -0
- omlish/http/flasky/requests.py +20 -0
- omlish/http/flasky/responses.py +23 -0
- omlish/http/flasky/routes.py +23 -0
- omlish/http/flasky/types.py +15 -0
- omlish/http/urls.py +67 -0
- omlish/inject/__init__.py +57 -29
- omlish/inject/_dataclasses.py +5148 -0
- omlish/inject/binder.py +11 -52
- omlish/inject/eagers.py +2 -0
- omlish/inject/elements.py +27 -0
- omlish/inject/helpers/__init__.py +0 -0
- omlish/inject/{utils.py → helpers/constfn.py} +3 -3
- omlish/inject/{tags.py → helpers/id.py} +2 -2
- omlish/inject/helpers/late.py +76 -0
- omlish/inject/{managed.py → helpers/managed.py} +10 -10
- omlish/inject/helpers/multis.py +143 -0
- omlish/inject/helpers/wrappers.py +54 -0
- omlish/inject/impl/elements.py +54 -21
- omlish/inject/impl/injector.py +29 -25
- omlish/inject/impl/inspect.py +10 -1
- omlish/inject/impl/maysync.py +3 -4
- omlish/inject/impl/multis.py +3 -0
- omlish/inject/impl/sync.py +3 -4
- omlish/inject/injector.py +31 -2
- omlish/inject/inspect.py +35 -0
- omlish/inject/maysync.py +2 -4
- omlish/inject/multis.py +8 -0
- omlish/inject/overrides.py +3 -3
- omlish/inject/privates.py +6 -0
- omlish/inject/providers.py +3 -2
- omlish/inject/sync.py +5 -4
- omlish/io/buffers.py +118 -0
- omlish/io/readers.py +29 -0
- omlish/iterators/transforms.py +2 -2
- omlish/lang/__init__.py +180 -97
- omlish/lang/_asyncs.cc +186 -0
- omlish/lang/asyncs.py +17 -0
- omlish/lang/casing.py +11 -0
- omlish/lang/contextmanagers.py +28 -4
- omlish/lang/functions.py +31 -22
- omlish/lang/imports/_capture.cc +11 -9
- omlish/lang/imports/capture.py +363 -170
- omlish/lang/imports/proxy.py +455 -152
- omlish/lang/lazyglobals.py +22 -9
- omlish/lang/params.py +17 -0
- omlish/lang/recursion.py +0 -1
- omlish/lang/sequences.py +124 -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/abstract.py +54 -24
- omlish/lite/asyncs.py +2 -2
- omlish/lite/attrops.py +2 -0
- omlish/lite/contextmanagers.py +4 -4
- omlish/lite/dataclasses.py +44 -0
- omlish/lite/maybes.py +8 -0
- omlish/lite/maysync.py +1 -5
- omlish/lite/pycharm.py +1 -1
- omlish/lite/typing.py +24 -0
- omlish/logs/_amalg.py +1 -1
- omlish/logs/all.py +25 -11
- omlish/logs/asyncs.py +73 -0
- omlish/logs/base.py +101 -12
- 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 +17 -2
- omlish/manifests/loading.py +2 -1
- omlish/marshal/__init__.py +33 -13
- omlish/marshal/_dataclasses.py +2774 -0
- omlish/marshal/base/configs.py +12 -0
- omlish/marshal/base/contexts.py +36 -21
- omlish/marshal/base/funcs.py +8 -11
- omlish/marshal/base/options.py +8 -0
- omlish/marshal/base/registries.py +146 -44
- omlish/marshal/base/types.py +40 -16
- omlish/marshal/composite/iterables.py +33 -20
- omlish/marshal/composite/literals.py +20 -18
- omlish/marshal/composite/mappings.py +36 -23
- omlish/marshal/composite/maybes.py +29 -19
- omlish/marshal/composite/newtypes.py +16 -16
- omlish/marshal/composite/optionals.py +14 -14
- omlish/marshal/composite/special.py +15 -15
- omlish/marshal/composite/unions/__init__.py +0 -0
- omlish/marshal/composite/unions/literals.py +93 -0
- omlish/marshal/composite/unions/primitives.py +103 -0
- omlish/marshal/factories/invalidate.py +18 -68
- omlish/marshal/factories/method.py +26 -0
- omlish/marshal/factories/moduleimport/factories.py +22 -65
- omlish/marshal/factories/multi.py +13 -25
- omlish/marshal/factories/recursive.py +42 -56
- omlish/marshal/factories/typecache.py +29 -74
- omlish/marshal/factories/typemap.py +42 -43
- omlish/marshal/objects/dataclasses.py +129 -106
- omlish/marshal/objects/marshal.py +18 -14
- omlish/marshal/objects/namedtuples.py +48 -42
- omlish/marshal/objects/unmarshal.py +19 -15
- omlish/marshal/polymorphism/marshal.py +9 -11
- omlish/marshal/polymorphism/metadata.py +16 -5
- omlish/marshal/polymorphism/standard.py +13 -1
- omlish/marshal/polymorphism/unions.py +15 -105
- omlish/marshal/polymorphism/unmarshal.py +9 -10
- omlish/marshal/singular/enums.py +14 -18
- omlish/marshal/standard.py +10 -6
- omlish/marshal/trivial/any.py +1 -1
- omlish/marshal/trivial/forbidden.py +21 -26
- omlish/metadata.py +23 -1
- omlish/os/forkhooks.py +4 -0
- omlish/os/pidfiles/pinning.py +2 -2
- omlish/reflect/__init__.py +43 -26
- omlish/reflect/ops.py +10 -1
- omlish/reflect/types.py +1 -0
- omlish/secrets/marshal.py +1 -1
- omlish/specs/jmespath/__init__.py +12 -3
- omlish/specs/jmespath/_dataclasses.py +2893 -0
- omlish/specs/jmespath/ast.py +1 -1
- omlish/specs/jsonrpc/__init__.py +13 -0
- omlish/specs/jsonrpc/_marshal.py +32 -23
- omlish/specs/jsonrpc/conns.py +10 -7
- omlish/specs/jsonschema/_marshal.py +1 -1
- omlish/specs/jsonschema/keywords/__init__.py +7 -0
- omlish/specs/jsonschema/keywords/_dataclasses.py +1644 -0
- omlish/specs/openapi/_marshal.py +31 -22
- omlish/sql/__init__.py +24 -5
- omlish/sql/{tabledefs/alchemy.py → alchemy/tabledefs.py} +2 -2
- 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/sql/queries/_marshal.py +2 -2
- omlish/sql/queries/rendering.py +1 -1
- omlish/sql/tabledefs/_marshal.py +1 -1
- omlish/subprocesses/base.py +4 -0
- omlish/subprocesses/editor.py +1 -1
- omlish/sync.py +155 -21
- omlish/term/alt.py +60 -0
- omlish/term/confirm.py +8 -8
- omlish/term/pager.py +235 -0
- omlish/term/terminfo.py +935 -0
- omlish/term/termstate.py +67 -0
- omlish/term/vt100/terminal.py +0 -3
- omlish/testing/pytest/plugins/asyncs/fixtures.py +4 -1
- omlish/testing/pytest/plugins/asyncs/plugin.py +2 -0
- omlish/testing/pytest/plugins/skips.py +2 -1
- omlish/testing/unittest/main.py +3 -3
- omlish/text/docwrap/__init__.py +3 -0
- omlish/text/docwrap/__main__.py +11 -0
- omlish/text/docwrap/api.py +83 -0
- omlish/text/docwrap/cli.py +91 -0
- omlish/text/docwrap/groups.py +84 -0
- omlish/text/docwrap/lists.py +167 -0
- omlish/text/docwrap/parts.py +146 -0
- omlish/text/docwrap/reflowing.py +106 -0
- omlish/text/docwrap/rendering.py +151 -0
- omlish/text/docwrap/utils.py +11 -0
- omlish/text/docwrap/wrapping.py +59 -0
- omlish/text/filecache.py +2 -2
- omlish/text/lorem.py +6 -0
- omlish/text/parts.py +2 -2
- omlish/text/textwrap.py +51 -0
- omlish/typedvalues/marshal.py +85 -59
- omlish/typedvalues/values.py +2 -1
- {omlish-0.0.0.dev447.dist-info → omlish-0.0.0.dev493.dist-info}/METADATA +36 -32
- {omlish-0.0.0.dev447.dist-info → omlish-0.0.0.dev493.dist-info}/RECORD +260 -199
- omlish/dataclasses/impl/generation/mangling.py +0 -18
- omlish/funcs/match.py +0 -227
- omlish/lifecycles/abstract.py +0 -86
- omlish/marshal/factories/match.py +0 -34
- omlish/marshal/factories/simple.py +0 -28
- /omlish/inject/{impl → helpers}/proxy.py +0 -0
- /omlish/inject/impl/{providers2.py → providersmap.py} +0 -0
- /omlish/sql/{abc.py → dbapi/abc.py} +0 -0
- {omlish-0.0.0.dev447.dist-info → omlish-0.0.0.dev493.dist-info}/WHEEL +0 -0
- {omlish-0.0.0.dev447.dist-info → omlish-0.0.0.dev493.dist-info}/entry_points.txt +0 -0
- {omlish-0.0.0.dev447.dist-info → omlish-0.0.0.dev493.dist-info}/licenses/LICENSE +0 -0
- {omlish-0.0.0.dev447.dist-info → omlish-0.0.0.dev493.dist-info}/top_level.txt +0 -0
omlish/inject/binder.py
CHANGED
|
@@ -11,13 +11,8 @@ from .bindings import Binding
|
|
|
11
11
|
from .eagers import Eager
|
|
12
12
|
from .elements import Element
|
|
13
13
|
from .elements import Elements
|
|
14
|
-
from .elements import as_elements
|
|
15
14
|
from .keys import Key
|
|
16
15
|
from .keys import as_key
|
|
17
|
-
from .multis import MapBinding
|
|
18
|
-
from .multis import SetBinding
|
|
19
|
-
from .multis import is_map_multi_key
|
|
20
|
-
from .multis import is_set_multi_key
|
|
21
16
|
from .privates import Expose
|
|
22
17
|
from .providers import AsyncFnProvider
|
|
23
18
|
from .providers import ConstProvider
|
|
@@ -27,7 +22,6 @@ from .providers import LinkProvider
|
|
|
27
22
|
from .providers import Provider
|
|
28
23
|
from .scopes import SCOPE_ALIASES
|
|
29
24
|
from .scopes import Singleton
|
|
30
|
-
from .tags import Id
|
|
31
25
|
from .types import Scope
|
|
32
26
|
from .types import Unscoped
|
|
33
27
|
|
|
@@ -84,6 +78,7 @@ def bind(
|
|
|
84
78
|
*,
|
|
85
79
|
tag: ta.Any = None,
|
|
86
80
|
|
|
81
|
+
to_provider: Provider | None = None,
|
|
87
82
|
to_async_fn: ta.Any = None,
|
|
88
83
|
to_fn: ta.Any = None,
|
|
89
84
|
to_ctor: ta.Any = None,
|
|
@@ -93,7 +88,7 @@ def bind(
|
|
|
93
88
|
in_: Scope | None = None,
|
|
94
89
|
singleton: bool = False,
|
|
95
90
|
|
|
96
|
-
eager: bool = False,
|
|
91
|
+
eager: bool | int = False,
|
|
97
92
|
expose: bool = False,
|
|
98
93
|
) -> Element | Elements:
|
|
99
94
|
if obj is None or obj is inspect.Parameter.empty:
|
|
@@ -104,6 +99,7 @@ def bind(
|
|
|
104
99
|
##
|
|
105
100
|
|
|
106
101
|
has_to = (
|
|
102
|
+
to_provider is not None or
|
|
107
103
|
to_async_fn is not None or
|
|
108
104
|
to_fn is not None or
|
|
109
105
|
to_ctor is not None or
|
|
@@ -121,7 +117,10 @@ def bind(
|
|
|
121
117
|
elif _is_fn(obj) and not has_to:
|
|
122
118
|
sig = _inspect.signature(obj)
|
|
123
119
|
ty = rfl.type_(sig.return_annotation)
|
|
124
|
-
|
|
120
|
+
if inspect.iscoroutinefunction(obj):
|
|
121
|
+
to_async_fn = obj
|
|
122
|
+
else:
|
|
123
|
+
to_fn = obj
|
|
125
124
|
key = Key(ty)
|
|
126
125
|
else:
|
|
127
126
|
if to_const is not None:
|
|
@@ -140,6 +139,8 @@ def bind(
|
|
|
140
139
|
##
|
|
141
140
|
|
|
142
141
|
providers: list[Provider] = []
|
|
142
|
+
if to_provider is not None:
|
|
143
|
+
providers.append(to_provider)
|
|
143
144
|
if to_async_fn is not None:
|
|
144
145
|
providers.append(AsyncFnProvider(to_async_fn))
|
|
145
146
|
if to_fn is not None:
|
|
@@ -182,8 +183,8 @@ def bind(
|
|
|
182
183
|
|
|
183
184
|
elements: list[Element] = [binding]
|
|
184
185
|
|
|
185
|
-
if eager:
|
|
186
|
-
elements.append(Eager(key))
|
|
186
|
+
if eager is not False:
|
|
187
|
+
elements.append(Eager(key, priority=eager if isinstance(eager, int) else 0))
|
|
187
188
|
if expose:
|
|
188
189
|
elements.append(Expose(key))
|
|
189
190
|
|
|
@@ -191,45 +192,3 @@ def bind(
|
|
|
191
192
|
return elements[0]
|
|
192
193
|
else:
|
|
193
194
|
return Elements(frozenset(elements))
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
##
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
def bind_set_entry_const(
|
|
200
|
-
multi_key: ta.Any,
|
|
201
|
-
obj: ta.Any,
|
|
202
|
-
*,
|
|
203
|
-
tag: ta.Any | None = None,
|
|
204
|
-
) -> Elements:
|
|
205
|
-
multi_key = as_key(multi_key)
|
|
206
|
-
check.arg(is_set_multi_key(multi_key))
|
|
207
|
-
|
|
208
|
-
if tag is None:
|
|
209
|
-
tag = Id(id(obj), tag=multi_key.tag)
|
|
210
|
-
obj_key: Key = Key(type(obj), tag=tag)
|
|
211
|
-
|
|
212
|
-
return as_elements(
|
|
213
|
-
bind(obj_key, to_const=obj),
|
|
214
|
-
SetBinding(multi_key, obj_key),
|
|
215
|
-
)
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
def bind_map_entry_const(
|
|
219
|
-
multi_key: ta.Any,
|
|
220
|
-
map_key: ta.Any,
|
|
221
|
-
obj: ta.Any,
|
|
222
|
-
*,
|
|
223
|
-
tag: ta.Any | None = None,
|
|
224
|
-
) -> Elements:
|
|
225
|
-
multi_key = as_key(multi_key)
|
|
226
|
-
check.arg(is_map_multi_key(multi_key))
|
|
227
|
-
|
|
228
|
-
if tag is None:
|
|
229
|
-
tag = Id(id(obj), tag=multi_key.tag)
|
|
230
|
-
obj_key: Key = Key(type(obj), tag=tag)
|
|
231
|
-
|
|
232
|
-
return as_elements(
|
|
233
|
-
bind(obj_key, to_const=obj),
|
|
234
|
-
MapBinding(multi_key, map_key, obj_key),
|
|
235
|
-
)
|
omlish/inject/eagers.py
CHANGED
omlish/inject/elements.py
CHANGED
|
@@ -6,6 +6,12 @@ from .. import lang
|
|
|
6
6
|
from .impl.origins import HasOriginsImpl
|
|
7
7
|
|
|
8
8
|
|
|
9
|
+
if ta.TYPE_CHECKING:
|
|
10
|
+
from .impl import elements as _elements
|
|
11
|
+
else:
|
|
12
|
+
_elements = lang.proxy_import('.impl.elements', __package__)
|
|
13
|
+
|
|
14
|
+
|
|
9
15
|
##
|
|
10
16
|
|
|
11
17
|
|
|
@@ -64,3 +70,24 @@ def as_elements(*args: Elemental) -> Elements:
|
|
|
64
70
|
es if es else None,
|
|
65
71
|
cs if cs else None,
|
|
66
72
|
)
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def iter_elements(*args: Elemental) -> ta.Iterator[Element]:
|
|
76
|
+
for a in args:
|
|
77
|
+
if isinstance(a, Element):
|
|
78
|
+
yield a
|
|
79
|
+
elif isinstance(a, (Elements, ElementGenerator)):
|
|
80
|
+
yield from a
|
|
81
|
+
else:
|
|
82
|
+
raise TypeError(a)
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
##
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
class CollectedElements(lang.PackageSealed, lang.Abstract):
|
|
89
|
+
pass
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def collect_elements(es: Elements | CollectedElements) -> CollectedElements:
|
|
93
|
+
return _elements.collect_elements(es)
|
|
File without changes
|
|
@@ -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))
|
|
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')
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import typing as ta
|
|
2
|
+
|
|
3
|
+
from ... import cached
|
|
4
|
+
from ... import check
|
|
5
|
+
from ... import dataclasses as dc
|
|
6
|
+
from ... import lang
|
|
7
|
+
from ... import reflect as rfl
|
|
8
|
+
from ..binder import bind
|
|
9
|
+
from ..elements import Elements
|
|
10
|
+
from ..elements import as_elements
|
|
11
|
+
from ..inspect import KwargsTarget
|
|
12
|
+
from ..keys import Key
|
|
13
|
+
from ..keys import as_key
|
|
14
|
+
from ..multis import MapBinding
|
|
15
|
+
from ..multis import SetBinder
|
|
16
|
+
from ..multis import SetBinding
|
|
17
|
+
from ..multis import is_map_multi_key
|
|
18
|
+
from ..multis import is_set_multi_key
|
|
19
|
+
from ..providers import FnProvider
|
|
20
|
+
from .id import Id
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
ItemT = ta.TypeVar('ItemT')
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
##
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def bind_set_entry_const(
|
|
30
|
+
multi_key: ta.Any,
|
|
31
|
+
obj: ta.Any,
|
|
32
|
+
*,
|
|
33
|
+
tag: ta.Any | None = None,
|
|
34
|
+
) -> Elements:
|
|
35
|
+
multi_key = as_key(multi_key)
|
|
36
|
+
check.arg(is_set_multi_key(multi_key))
|
|
37
|
+
|
|
38
|
+
if tag is None:
|
|
39
|
+
tag = Id(id(obj), tag=multi_key.tag)
|
|
40
|
+
obj_key: Key = Key(type(obj), tag=tag)
|
|
41
|
+
|
|
42
|
+
return as_elements(
|
|
43
|
+
bind(obj_key, to_const=obj),
|
|
44
|
+
SetBinding(multi_key, obj_key),
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def bind_map_entry_const(
|
|
49
|
+
multi_key: ta.Any,
|
|
50
|
+
map_key: ta.Any,
|
|
51
|
+
obj: ta.Any,
|
|
52
|
+
*,
|
|
53
|
+
tag: ta.Any | None = None,
|
|
54
|
+
) -> Elements:
|
|
55
|
+
multi_key = as_key(multi_key)
|
|
56
|
+
check.arg(is_map_multi_key(multi_key))
|
|
57
|
+
|
|
58
|
+
if tag is None:
|
|
59
|
+
tag = Id(id(obj), tag=multi_key.tag)
|
|
60
|
+
obj_key: Key = Key(type(obj), tag=tag)
|
|
61
|
+
|
|
62
|
+
return as_elements(
|
|
63
|
+
bind(obj_key, to_const=obj),
|
|
64
|
+
MapBinding(multi_key, map_key, obj_key),
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
##
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
@ta.final
|
|
72
|
+
class ItemsBinderHelper(ta.Generic[ItemT]):
|
|
73
|
+
def __init__(self, items_cls: ta.Any) -> None:
|
|
74
|
+
self._items_cls = items_cls
|
|
75
|
+
|
|
76
|
+
@cached.property
|
|
77
|
+
def _item_rty(self) -> rfl.Type:
|
|
78
|
+
rty = check.isinstance(rfl.type_(rfl.get_orig_class(self)), rfl.Generic)
|
|
79
|
+
check.is_(rty.cls, self.__class__)
|
|
80
|
+
return check.single(rty.args)
|
|
81
|
+
|
|
82
|
+
@dc.dataclass(frozen=True, eq=False)
|
|
83
|
+
class _ItemsBox:
|
|
84
|
+
vs: ta.Sequence
|
|
85
|
+
|
|
86
|
+
@cached.property
|
|
87
|
+
def _items_box(self) -> type[_ItemsBox]:
|
|
88
|
+
if isinstance(item_rty := self._item_rty, type):
|
|
89
|
+
sfx = item_rty.__qualname__
|
|
90
|
+
else:
|
|
91
|
+
sfx = str(item_rty).replace("'", '')
|
|
92
|
+
|
|
93
|
+
return lang.new_type( # noqa
|
|
94
|
+
f'{ItemsBinderHelper._ItemsBox.__qualname__}${sfx}@{id(self):x}',
|
|
95
|
+
(ItemsBinderHelper._ItemsBox,),
|
|
96
|
+
{},
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
@cached.property
|
|
100
|
+
def _set_key(self) -> Key:
|
|
101
|
+
return as_key(ta.AbstractSet[self._item_rty]) # type: ignore
|
|
102
|
+
|
|
103
|
+
def bind_item_consts(self, *items: ItemT) -> Elements:
|
|
104
|
+
return as_elements(
|
|
105
|
+
bind_set_entry_const(self._set_key, self._items_box(items)),
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
@dc.dataclass(frozen=True, eq=False)
|
|
109
|
+
@dc.extra_class_params(repr_id=True)
|
|
110
|
+
class _ItemTag:
|
|
111
|
+
pass
|
|
112
|
+
|
|
113
|
+
def bind_item(self, **kwargs: ta.Any) -> Elements:
|
|
114
|
+
tag = ItemsBinderHelper._ItemTag()
|
|
115
|
+
item_key: Key = Key(ta.Any, tag=tag)
|
|
116
|
+
items_box_key: Key = Key(self._items_box, tag=tag)
|
|
117
|
+
return as_elements(
|
|
118
|
+
bind(item_key, **kwargs),
|
|
119
|
+
bind(
|
|
120
|
+
items_box_key,
|
|
121
|
+
to_provider=FnProvider(KwargsTarget.of(
|
|
122
|
+
lambda v: self._items_box([v]),
|
|
123
|
+
v=item_key,
|
|
124
|
+
)),
|
|
125
|
+
),
|
|
126
|
+
SetBinding(self._set_key, items_box_key),
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
def bind_items_provider(self, **kwargs: ta.Any) -> Elements:
|
|
130
|
+
return as_elements(
|
|
131
|
+
SetBinder[self._item_rty](), # type: ignore
|
|
132
|
+
bind(
|
|
133
|
+
self._items_cls,
|
|
134
|
+
to_provider=FnProvider(KwargsTarget.of(
|
|
135
|
+
lambda s: self._items_cls([v for i in s for v in i.vs]),
|
|
136
|
+
s=self._set_key,
|
|
137
|
+
)),
|
|
138
|
+
**kwargs,
|
|
139
|
+
),
|
|
140
|
+
)
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
items_binder_helper = ItemsBinderHelper
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import typing as ta
|
|
2
|
+
|
|
3
|
+
from ... import cached
|
|
4
|
+
from ... import dataclasses as dc
|
|
5
|
+
from ..binder import bind
|
|
6
|
+
from ..elements import Elemental
|
|
7
|
+
from ..keys import Key
|
|
8
|
+
from ..keys import as_key
|
|
9
|
+
from ..privates import private
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
##
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@ta.final
|
|
16
|
+
class WrapperBinderHelper:
|
|
17
|
+
def __init__(self, key: ta.Any) -> None:
|
|
18
|
+
self._key = as_key(key)
|
|
19
|
+
self._root = WrapperBinderHelper._Root()
|
|
20
|
+
self._top = WrapperBinderHelper._Level(self._root, 0)
|
|
21
|
+
|
|
22
|
+
@dc.dataclass(frozen=True, eq=False)
|
|
23
|
+
@dc.extra_class_params(repr_id=True)
|
|
24
|
+
class _Root:
|
|
25
|
+
pass
|
|
26
|
+
|
|
27
|
+
@dc.dataclass(frozen=True)
|
|
28
|
+
class _Level:
|
|
29
|
+
root: 'WrapperBinderHelper._Root'
|
|
30
|
+
level: int
|
|
31
|
+
|
|
32
|
+
def next(self) -> 'WrapperBinderHelper._Level':
|
|
33
|
+
return WrapperBinderHelper._Level(self.root, self.level + 1)
|
|
34
|
+
|
|
35
|
+
@cached.property
|
|
36
|
+
def key(self) -> Key:
|
|
37
|
+
return Key(ta.Any, tag=self)
|
|
38
|
+
|
|
39
|
+
@property
|
|
40
|
+
def top(self) -> Key:
|
|
41
|
+
return self._top.key
|
|
42
|
+
|
|
43
|
+
def push_bind(self, **kwargs: ta.Any) -> Elemental:
|
|
44
|
+
prv = self._top
|
|
45
|
+
nxt = prv.next()
|
|
46
|
+
out = private(
|
|
47
|
+
*([bind(self._key, to_key=prv.key)] if prv.level else []),
|
|
48
|
+
bind(nxt.key, **kwargs, expose=True),
|
|
49
|
+
)
|
|
50
|
+
self._top = nxt
|
|
51
|
+
return out
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
wrapper_binder_helper = WrapperBinderHelper
|
omlish/inject/impl/elements.py
CHANGED
|
@@ -27,6 +27,7 @@ from ... import collections as col
|
|
|
27
27
|
from ... import lang
|
|
28
28
|
from ..bindings import Binding
|
|
29
29
|
from ..eagers import Eager
|
|
30
|
+
from ..elements import CollectedElements
|
|
30
31
|
from ..elements import Element
|
|
31
32
|
from ..elements import Elements
|
|
32
33
|
from ..errors import ConflictingKeyError
|
|
@@ -47,7 +48,7 @@ from .multis import make_multi_provider_impl
|
|
|
47
48
|
from .origins import Origins
|
|
48
49
|
from .origins import set_origins
|
|
49
50
|
from .providers import ProviderImpl
|
|
50
|
-
from .
|
|
51
|
+
from .providersmap import make_provider_impl
|
|
51
52
|
from .scopes import make_scope_impl
|
|
52
53
|
|
|
53
54
|
|
|
@@ -63,7 +64,24 @@ ElementT = ta.TypeVar('ElementT', bound=Element)
|
|
|
63
64
|
##
|
|
64
65
|
|
|
65
66
|
|
|
66
|
-
|
|
67
|
+
_SIMPLE_KEYED_ELEMENT_TYPES: tuple[type[Element], ...] = (
|
|
68
|
+
Binding,
|
|
69
|
+
Eager,
|
|
70
|
+
Expose,
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
_SIMPLE_NON_KEYED_ELEMENT_TYPES: tuple[type[Element], ...] = (
|
|
74
|
+
ProvisionListenerBinding,
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
_NON_BINDING_ELEMENT_TYPES: tuple[type[Element], ...] = (
|
|
78
|
+
Eager,
|
|
79
|
+
Expose,
|
|
80
|
+
ProvisionListenerBinding,
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
class ElementCollection(CollectedElements, lang.Final):
|
|
67
85
|
def __init__(self, es: Elements) -> None:
|
|
68
86
|
super().__init__()
|
|
69
87
|
|
|
@@ -96,28 +114,28 @@ class ElementCollection(lang.Final):
|
|
|
96
114
|
out.setdefault(k, []).extend(e)
|
|
97
115
|
|
|
98
116
|
for e in es:
|
|
99
|
-
if isinstance(e,
|
|
117
|
+
if isinstance(e, _SIMPLE_KEYED_ELEMENT_TYPES):
|
|
118
|
+
add(e.key, e) # type: ignore[attr-defined] # noqa
|
|
119
|
+
|
|
120
|
+
elif isinstance(e, _SIMPLE_NON_KEYED_ELEMENT_TYPES):
|
|
121
|
+
add(None, e)
|
|
122
|
+
|
|
123
|
+
elif isinstance(e, (SetBinding, MapBinding)):
|
|
124
|
+
add(e.multi_key, e)
|
|
125
|
+
|
|
126
|
+
elif isinstance(e, ScopeBinding):
|
|
100
127
|
add(None, e)
|
|
101
128
|
sci = make_scope_impl(e.scope)
|
|
102
129
|
if (sae := sci.auto_elements()) is not None:
|
|
103
130
|
self._build_raw_element_multimap(sae, out)
|
|
104
131
|
|
|
105
|
-
elif isinstance(e, (Binding, Eager, Expose)):
|
|
106
|
-
add(e.key, e)
|
|
107
|
-
|
|
108
132
|
elif isinstance(e, Private):
|
|
109
133
|
pi = self._get_private_info(e)
|
|
110
134
|
self._build_raw_element_multimap(pi.owner_elements(), out)
|
|
111
135
|
|
|
112
|
-
elif isinstance(e, (SetBinding, MapBinding)):
|
|
113
|
-
add(e.multi_key, e)
|
|
114
|
-
|
|
115
|
-
elif isinstance(e, ProvisionListenerBinding):
|
|
116
|
-
add(None, e)
|
|
117
|
-
|
|
118
136
|
elif isinstance(e, Overrides):
|
|
119
|
-
ovr = self._build_raw_element_multimap(e.ovr)
|
|
120
137
|
src = self._build_raw_element_multimap(e.src)
|
|
138
|
+
ovr = self._build_raw_element_multimap(e.ovr)
|
|
121
139
|
for k, b in src.items(): # FIXME: merge None keys?
|
|
122
140
|
try:
|
|
123
141
|
bs = ovr[k]
|
|
@@ -166,9 +184,8 @@ class ElementCollection(lang.Final):
|
|
|
166
184
|
|
|
167
185
|
es_by_ty = col.multi_map_by(type, es)
|
|
168
186
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
es_by_ty.pop(ProvisionListenerBinding, None)
|
|
187
|
+
for nb_ty in _NON_BINDING_ELEMENT_TYPES:
|
|
188
|
+
es_by_ty.pop(nb_ty, None)
|
|
172
189
|
|
|
173
190
|
if (bs := es_by_ty.pop(Binding, None)):
|
|
174
191
|
b = self._get_single_binding(k, bs) # type: ignore
|
|
@@ -176,7 +193,6 @@ class ElementCollection(lang.Final):
|
|
|
176
193
|
p: ProviderImpl
|
|
177
194
|
if isinstance(b.provider, (SetProvider, MapProvider)):
|
|
178
195
|
p = make_multi_provider_impl(b.provider, es_by_ty)
|
|
179
|
-
|
|
180
196
|
else:
|
|
181
197
|
p = make_provider_impl(b.provider)
|
|
182
198
|
|
|
@@ -194,10 +210,27 @@ class ElementCollection(lang.Final):
|
|
|
194
210
|
##
|
|
195
211
|
|
|
196
212
|
@lang.cached_function
|
|
197
|
-
def
|
|
213
|
+
def scope_binding_scopes(self) -> ta.Sequence[Scope]:
|
|
214
|
+
return [sb.scope for sb in self.elements_of_type(ScopeBinding)]
|
|
215
|
+
|
|
216
|
+
@lang.cached_function
|
|
217
|
+
def sorted_eager_keys_by_scope(self) -> ta.Mapping[Scope, ta.Sequence[Key]]:
|
|
198
218
|
bim = self.binding_impl_map()
|
|
199
|
-
|
|
219
|
+
dct: dict[Scope, list[Eager]] = {}
|
|
200
220
|
for e in self.elements_of_type(Eager):
|
|
201
221
|
bi = bim[e.key]
|
|
202
|
-
|
|
203
|
-
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
|
+
}
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
##
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
def collect_elements(es: Elements | CollectedElements) -> ElementCollection:
|
|
233
|
+
if isinstance(es, CollectedElements):
|
|
234
|
+
return check.isinstance(es, ElementCollection)
|
|
235
|
+
else:
|
|
236
|
+
return ElementCollection(es)
|