omlish 0.0.0.dev447__py3-none-any.whl → 0.0.0.dev484__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/__about__.py +15 -15
- 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/processor.py +105 -24
- omlish/dataclasses/impl/processing/base.py +8 -0
- omlish/dataclasses/impl/processing/driving.py +8 -8
- omlish/dataclasses/specs.py +1 -0
- omlish/dataclasses/tools/modifiers.py +5 -0
- 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 +38 -18
- omlish/inject/_dataclasses.py +4986 -0
- omlish/inject/binder.py +4 -48
- 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/multis.py +143 -0
- omlish/inject/helpers/wrappers.py +54 -0
- omlish/inject/impl/elements.py +47 -17
- omlish/inject/impl/injector.py +20 -19
- 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 +178 -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/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 +6 -0
- omlish/logs/all.py +1 -1
- omlish/logs/utils.py +1 -1
- 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/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/{tabledefs/alchemy.py → alchemy/tabledefs.py} +2 -2
- 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/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 +86 -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.dev484.dist-info}/METADATA +29 -28
- {omlish-0.0.0.dev447.dist-info → omlish-0.0.0.dev484.dist-info}/RECORD +222 -171
- omlish/dataclasses/impl/generation/mangling.py +0 -18
- omlish/funcs/match.py +0 -227
- omlish/marshal/factories/match.py +0 -34
- omlish/marshal/factories/simple.py +0 -28
- /omlish/inject/impl/{providers2.py → providersmap.py} +0 -0
- {omlish-0.0.0.dev447.dist-info → omlish-0.0.0.dev484.dist-info}/WHEEL +0 -0
- {omlish-0.0.0.dev447.dist-info → omlish-0.0.0.dev484.dist-info}/entry_points.txt +0 -0
- {omlish-0.0.0.dev447.dist-info → omlish-0.0.0.dev484.dist-info}/licenses/LICENSE +0 -0
- {omlish-0.0.0.dev447.dist-info → omlish-0.0.0.dev484.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,
|
|
@@ -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
|
|
@@ -140,6 +136,8 @@ def bind(
|
|
|
140
136
|
##
|
|
141
137
|
|
|
142
138
|
providers: list[Provider] = []
|
|
139
|
+
if to_provider is not None:
|
|
140
|
+
providers.append(to_provider)
|
|
143
141
|
if to_async_fn is not None:
|
|
144
142
|
providers.append(AsyncFnProvider(to_async_fn))
|
|
145
143
|
if to_fn is not None:
|
|
@@ -191,45 +189,3 @@ def bind(
|
|
|
191
189
|
return elements[0]
|
|
192
190
|
else:
|
|
193
191
|
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/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,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
|
|
|
@@ -193,6 +209,10 @@ class ElementCollection(lang.Final):
|
|
|
193
209
|
|
|
194
210
|
##
|
|
195
211
|
|
|
212
|
+
@lang.cached_function
|
|
213
|
+
def scope_binding_scopes(self) -> ta.Sequence[Scope]:
|
|
214
|
+
return [sb.scope for sb in self.elements_of_type(ScopeBinding)]
|
|
215
|
+
|
|
196
216
|
@lang.cached_function
|
|
197
217
|
def eager_keys_by_scope(self) -> ta.Mapping[Scope, ta.Sequence[Key]]:
|
|
198
218
|
bim = self.binding_impl_map()
|
|
@@ -201,3 +221,13 @@ class ElementCollection(lang.Final):
|
|
|
201
221
|
bi = bim[e.key]
|
|
202
222
|
ret.setdefault(bi.scope, []).append(e.key)
|
|
203
223
|
return ret
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
##
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
def collect_elements(es: Elements | CollectedElements) -> ElementCollection:
|
|
230
|
+
if isinstance(es, CollectedElements):
|
|
231
|
+
return check.isinstance(es, ElementCollection)
|
|
232
|
+
else:
|
|
233
|
+
return ElementCollection(es)
|
omlish/inject/impl/injector.py
CHANGED
|
@@ -2,16 +2,16 @@
|
|
|
2
2
|
TODO:
|
|
3
3
|
- ** can currently bind in a child/private scope shadowing an external parent binding **
|
|
4
4
|
- better source tracking
|
|
5
|
-
- cache/export ElementCollections lol
|
|
6
5
|
- scope bindings, auto in root
|
|
7
6
|
- injector-internal / blacklisted bindings (Injector itself, default scopes) without rebuilding ElementCollection
|
|
8
7
|
- config - proxies, impl select, etc
|
|
9
8
|
- config is probably shared with ElementCollection... but not 'bound', must be shared everywhere
|
|
10
9
|
- InjectorRoot object?
|
|
11
10
|
- ** eagers in any scope, on scope init/open
|
|
12
|
-
- injection listeners
|
|
13
11
|
- unions - raise on ambiguous - usecase: sql.AsyncEngineLike
|
|
14
12
|
- multiple live request scopes on single injector - use private injectors?
|
|
13
|
+
- more listeners - UnboundKeyListener
|
|
14
|
+
- lazy parent listener chain cache thing
|
|
15
15
|
"""
|
|
16
16
|
import contextlib
|
|
17
17
|
import functools
|
|
@@ -22,7 +22,7 @@ import weakref
|
|
|
22
22
|
from ... import check
|
|
23
23
|
from ... import lang
|
|
24
24
|
from ...logs import all as logs
|
|
25
|
-
from ..elements import
|
|
25
|
+
from ..elements import CollectedElements
|
|
26
26
|
from ..errors import CyclicDependencyError
|
|
27
27
|
from ..errors import UnboundKeyError
|
|
28
28
|
from ..injector import AsyncInjector
|
|
@@ -31,7 +31,6 @@ from ..keys import Key
|
|
|
31
31
|
from ..keys import as_key
|
|
32
32
|
from ..listeners import ProvisionListener
|
|
33
33
|
from ..listeners import ProvisionListenerBinding
|
|
34
|
-
from ..scopes import ScopeBinding
|
|
35
34
|
from ..scopes import Singleton
|
|
36
35
|
from ..scopes import ThreadScope
|
|
37
36
|
from ..types import Scope
|
|
@@ -55,17 +54,16 @@ DEFAULT_SCOPES: list[Scope] = [
|
|
|
55
54
|
]
|
|
56
55
|
|
|
57
56
|
|
|
57
|
+
@ta.final
|
|
58
58
|
class AsyncInjectorImpl(AsyncInjector, lang.Final):
|
|
59
59
|
def __init__(
|
|
60
60
|
self,
|
|
61
|
-
ec:
|
|
61
|
+
ec: CollectedElements,
|
|
62
62
|
p: ta.Optional['AsyncInjectorImpl'] = None,
|
|
63
63
|
*,
|
|
64
64
|
internal_consts: dict[Key, ta.Any] | None = None,
|
|
65
65
|
) -> None:
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
self._ec = check.isinstance(ec, ElementCollection)
|
|
66
|
+
self._ec = (ec := check.isinstance(ec, ElementCollection))
|
|
69
67
|
self._p: AsyncInjectorImpl | None = check.isinstance(p, (AsyncInjectorImpl, None))
|
|
70
68
|
|
|
71
69
|
self._internal_consts: dict[Key, ta.Any] = {
|
|
@@ -74,28 +72,31 @@ class AsyncInjectorImpl(AsyncInjector, lang.Final):
|
|
|
74
72
|
}
|
|
75
73
|
|
|
76
74
|
self._bim = ec.binding_impl_map()
|
|
75
|
+
|
|
77
76
|
self._ekbs = ec.eager_keys_by_scope()
|
|
77
|
+
|
|
78
78
|
self._pls: tuple[ProvisionListener, ...] = tuple(
|
|
79
79
|
b.listener # type: ignore[attr-defined]
|
|
80
80
|
for b in itertools.chain(
|
|
81
81
|
ec.elements_of_type(ProvisionListenerBinding),
|
|
82
|
-
|
|
82
|
+
p._pls if p is not None else (), # noqa
|
|
83
83
|
)
|
|
84
84
|
)
|
|
85
85
|
|
|
86
|
-
self._cs: weakref.WeakSet[AsyncInjectorImpl] | None = None
|
|
87
86
|
self._root: AsyncInjectorImpl = p._root if p is not None else self # noqa
|
|
88
87
|
|
|
89
|
-
self.__cur_req: AsyncInjectorImpl._Request | None = None
|
|
90
|
-
|
|
91
|
-
ss = [
|
|
92
|
-
*DEFAULT_SCOPES,
|
|
93
|
-
*[sb.scope for sb in ec.elements_of_type(ScopeBinding)],
|
|
94
|
-
]
|
|
95
88
|
self._scopes: dict[Scope, ScopeImpl] = {
|
|
96
|
-
s: make_scope_impl(s)
|
|
89
|
+
s: make_scope_impl(s)
|
|
90
|
+
for s in itertools.chain(
|
|
91
|
+
DEFAULT_SCOPES,
|
|
92
|
+
ec.scope_binding_scopes(),
|
|
93
|
+
)
|
|
97
94
|
}
|
|
98
95
|
|
|
96
|
+
_cs: weakref.WeakSet['AsyncInjectorImpl'] | None = None # noqa
|
|
97
|
+
|
|
98
|
+
__cur_req: ta.Optional['AsyncInjectorImpl._Request'] = None
|
|
99
|
+
|
|
99
100
|
#
|
|
100
101
|
|
|
101
102
|
_has_run_init: bool = False
|
|
@@ -256,7 +257,7 @@ class AsyncInjectorImpl(AsyncInjector, lang.Final):
|
|
|
256
257
|
return obj(**kws)
|
|
257
258
|
|
|
258
259
|
|
|
259
|
-
async def create_async_injector(
|
|
260
|
-
i = AsyncInjectorImpl(
|
|
260
|
+
async def create_async_injector(ce: CollectedElements) -> AsyncInjector:
|
|
261
|
+
i = AsyncInjectorImpl(ce)
|
|
261
262
|
await i._init() # noqa
|
|
262
263
|
return i
|
omlish/inject/impl/inspect.py
CHANGED
|
@@ -75,7 +75,11 @@ def build_kwargs_target(
|
|
|
75
75
|
skip_args: int = 0,
|
|
76
76
|
skip_kwargs: ta.Iterable[str] | None = None,
|
|
77
77
|
raw_optional: bool = False,
|
|
78
|
+
non_strict: bool = False,
|
|
78
79
|
) -> KwargsTarget:
|
|
80
|
+
if isinstance(obj, KwargsTarget):
|
|
81
|
+
return obj
|
|
82
|
+
|
|
79
83
|
sig = signature(obj)
|
|
80
84
|
tags = _TAGS.get(obj)
|
|
81
85
|
|
|
@@ -90,11 +94,15 @@ def build_kwargs_target(
|
|
|
90
94
|
continue
|
|
91
95
|
|
|
92
96
|
if p.annotation is inspect.Signature.empty:
|
|
97
|
+
if non_strict:
|
|
98
|
+
continue
|
|
93
99
|
if p.default is not inspect.Parameter.empty:
|
|
94
100
|
raise KeyError(f'{obj}, {p.name}')
|
|
95
101
|
continue
|
|
96
102
|
|
|
97
103
|
if p.kind not in (inspect.Parameter.POSITIONAL_OR_KEYWORD, inspect.Parameter.KEYWORD_ONLY):
|
|
104
|
+
if non_strict:
|
|
105
|
+
continue
|
|
98
106
|
raise TypeError(sig)
|
|
99
107
|
|
|
100
108
|
ann = p.annotation
|
|
@@ -119,7 +127,8 @@ def build_kwargs_target(
|
|
|
119
127
|
k = dc.replace(k, tag=pt)
|
|
120
128
|
|
|
121
129
|
if k in seen:
|
|
122
|
-
|
|
130
|
+
if not non_strict:
|
|
131
|
+
raise ConflictingKeyError(k)
|
|
123
132
|
seen.add(k)
|
|
124
133
|
|
|
125
134
|
kws.append(Kwarg(
|
omlish/inject/impl/maysync.py
CHANGED
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
import typing as ta
|
|
2
2
|
|
|
3
3
|
from ... import lang
|
|
4
|
-
from ..elements import
|
|
4
|
+
from ..elements import CollectedElements
|
|
5
5
|
from ..injector import AsyncInjector
|
|
6
6
|
from ..inspect import KwargsTarget
|
|
7
7
|
from ..keys import Key
|
|
8
8
|
from ..maysync import MaysyncInjector
|
|
9
9
|
from ..sync import Injector
|
|
10
|
-
from .elements import ElementCollection
|
|
11
10
|
from .injector import AsyncInjectorImpl
|
|
12
11
|
|
|
13
12
|
|
|
@@ -30,10 +29,10 @@ class MaysyncInjectorImpl(MaysyncInjector, lang.Final):
|
|
|
30
29
|
return lang.run_maysync(self._ai.inject(obj))
|
|
31
30
|
|
|
32
31
|
|
|
33
|
-
def create_maysync_injector(
|
|
32
|
+
def create_maysync_injector(ce: CollectedElements) -> MaysyncInjector:
|
|
34
33
|
si = MaysyncInjectorImpl()
|
|
35
34
|
ai = AsyncInjectorImpl(
|
|
36
|
-
|
|
35
|
+
ce,
|
|
37
36
|
internal_consts={
|
|
38
37
|
Key(MaysyncInjector): si,
|
|
39
38
|
Key(Injector): si,
|
omlish/inject/impl/multis.py
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import typing as ta
|
|
2
2
|
|
|
3
|
+
from ... import check
|
|
3
4
|
from ... import dataclasses as dc
|
|
4
5
|
from ... import lang
|
|
5
6
|
from ..elements import Element
|
|
@@ -58,6 +59,7 @@ class MapProviderImpl(ProviderImpl, lang.Final):
|
|
|
58
59
|
def make_multi_provider_impl(p: Provider, es_by_ty: ta.MutableMapping[type, list[Element]]) -> ProviderImpl:
|
|
59
60
|
if isinstance(p, SetProvider):
|
|
60
61
|
sbs: ta.Iterable[SetBinding] = es_by_ty.pop(SetBinding, ()) # type: ignore
|
|
62
|
+
check.empty(es_by_ty)
|
|
61
63
|
return SetProviderImpl([
|
|
62
64
|
LinkProviderImpl(LinkProvider(sb.dst))
|
|
63
65
|
for sb in sbs
|
|
@@ -65,6 +67,7 @@ def make_multi_provider_impl(p: Provider, es_by_ty: ta.MutableMapping[type, list
|
|
|
65
67
|
|
|
66
68
|
elif isinstance(p, MapProvider):
|
|
67
69
|
mbs: ta.Iterable[MapBinding] = es_by_ty.pop(MapBinding, ()) # type: ignore
|
|
70
|
+
check.empty(es_by_ty)
|
|
68
71
|
return MapProviderImpl([
|
|
69
72
|
MapProviderImpl.Entry(
|
|
70
73
|
mb.map_key,
|
omlish/inject/impl/sync.py
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
import typing as ta
|
|
2
2
|
|
|
3
3
|
from ... import lang
|
|
4
|
-
from ..elements import
|
|
4
|
+
from ..elements import CollectedElements
|
|
5
5
|
from ..injector import AsyncInjector
|
|
6
6
|
from ..inspect import KwargsTarget
|
|
7
7
|
from ..keys import Key
|
|
8
8
|
from ..sync import Injector
|
|
9
|
-
from .elements import ElementCollection
|
|
10
9
|
from .injector import AsyncInjectorImpl
|
|
11
10
|
|
|
12
11
|
|
|
@@ -29,10 +28,10 @@ class InjectorImpl(Injector, lang.Final):
|
|
|
29
28
|
return lang.sync_await(self._ai.inject(obj))
|
|
30
29
|
|
|
31
30
|
|
|
32
|
-
def create_injector(
|
|
31
|
+
def create_injector(ce: CollectedElements) -> Injector:
|
|
33
32
|
si = InjectorImpl()
|
|
34
33
|
ai = AsyncInjectorImpl(
|
|
35
|
-
|
|
34
|
+
ce,
|
|
36
35
|
internal_consts={
|
|
37
36
|
Key(Injector): si,
|
|
38
37
|
},
|