omlish 0.0.0.dev5__py3-none-any.whl → 0.0.0.dev7__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of omlish might be problematic. Click here for more details.
- omlish/__about__.py +109 -5
- omlish/__init__.py +0 -8
- omlish/asyncs/__init__.py +9 -9
- omlish/asyncs/anyio.py +123 -19
- omlish/asyncs/asyncio.py +23 -0
- omlish/asyncs/asyncs.py +9 -6
- omlish/asyncs/bridge.py +316 -0
- omlish/asyncs/trio_asyncio.py +7 -3
- omlish/bootstrap.py +737 -0
- omlish/check.py +1 -1
- omlish/collections/__init__.py +5 -0
- omlish/collections/exceptions.py +2 -0
- omlish/collections/identity.py +7 -0
- omlish/collections/utils.py +38 -9
- omlish/configs/strings.py +96 -0
- omlish/dataclasses/__init__.py +16 -0
- omlish/dataclasses/impl/copy.py +30 -0
- omlish/dataclasses/impl/descriptors.py +95 -0
- omlish/dataclasses/impl/exceptions.py +6 -0
- omlish/dataclasses/impl/fields.py +24 -25
- omlish/dataclasses/impl/init.py +4 -2
- omlish/dataclasses/impl/main.py +2 -0
- omlish/dataclasses/impl/reflect.py +1 -1
- omlish/dataclasses/utils.py +67 -0
- omlish/{lang/datetimes.py → datetimes.py} +8 -4
- omlish/diag/__init__.py +4 -0
- omlish/diag/procfs.py +2 -2
- omlish/{testing → diag}/pydevd.py +35 -0
- omlish/diag/threads.py +131 -48
- omlish/dispatch/_dispatch2.py +65 -0
- omlish/dispatch/_dispatch3.py +104 -0
- omlish/docker.py +16 -1
- omlish/fnpairs.py +11 -4
- omlish/formats/__init__.py +0 -0
- omlish/{configs → formats}/dotenv.py +15 -24
- omlish/{json.py → formats/json.py} +2 -1
- omlish/formats/yaml.py +223 -0
- omlish/graphs/trees.py +1 -1
- omlish/http/asgi.py +2 -1
- omlish/http/collections.py +15 -0
- omlish/http/consts.py +22 -1
- omlish/http/sessions.py +10 -3
- omlish/inject/__init__.py +49 -17
- omlish/inject/binder.py +185 -5
- omlish/inject/bindings.py +3 -36
- omlish/inject/eagers.py +2 -8
- omlish/inject/elements.py +31 -10
- omlish/inject/exceptions.py +1 -1
- omlish/inject/impl/elements.py +37 -12
- omlish/inject/impl/injector.py +72 -25
- omlish/inject/impl/inspect.py +33 -5
- omlish/inject/impl/origins.py +77 -0
- omlish/inject/impl/{private.py → privates.py} +2 -2
- omlish/inject/impl/scopes.py +6 -2
- omlish/inject/injector.py +8 -4
- omlish/inject/inspect.py +18 -0
- omlish/inject/keys.py +8 -14
- omlish/inject/listeners.py +26 -0
- omlish/inject/managed.py +76 -10
- omlish/inject/multis.py +68 -18
- omlish/inject/origins.py +30 -0
- omlish/inject/overrides.py +5 -4
- omlish/inject/{private.py → privates.py} +6 -10
- omlish/inject/providers.py +12 -85
- omlish/inject/scopes.py +13 -6
- omlish/inject/types.py +3 -1
- omlish/inject/utils.py +18 -0
- omlish/iterators.py +69 -2
- omlish/lang/__init__.py +24 -9
- omlish/lang/cached.py +2 -2
- omlish/lang/classes/restrict.py +12 -1
- omlish/lang/classes/simple.py +18 -8
- omlish/lang/contextmanagers.py +13 -4
- omlish/lang/descriptors.py +132 -1
- omlish/lang/functions.py +8 -28
- omlish/lang/imports.py +67 -0
- omlish/lang/iterables.py +60 -1
- omlish/lang/maybes.py +3 -0
- omlish/lang/objects.py +38 -0
- omlish/lang/strings.py +25 -0
- omlish/lang/sys.py +9 -0
- omlish/lang/typing.py +42 -0
- omlish/lifecycles/__init__.py +34 -0
- omlish/lifecycles/abstract.py +43 -0
- omlish/lifecycles/base.py +51 -0
- omlish/lifecycles/contextmanagers.py +74 -0
- omlish/lifecycles/controller.py +116 -0
- omlish/lifecycles/manager.py +161 -0
- omlish/lifecycles/states.py +43 -0
- omlish/lifecycles/transitions.py +64 -0
- omlish/lite/__init__.py +1 -0
- omlish/lite/cached.py +18 -0
- omlish/lite/check.py +29 -0
- omlish/lite/contextmanagers.py +18 -0
- omlish/lite/json.py +30 -0
- omlish/lite/logs.py +52 -0
- omlish/lite/marshal.py +316 -0
- omlish/lite/reflect.py +49 -0
- omlish/lite/runtime.py +18 -0
- omlish/lite/secrets.py +19 -0
- omlish/lite/strings.py +25 -0
- omlish/lite/subprocesses.py +112 -0
- omlish/logs/configs.py +15 -2
- omlish/logs/formatters.py +7 -2
- omlish/marshal/__init__.py +32 -0
- omlish/marshal/any.py +5 -5
- omlish/marshal/base.py +27 -11
- omlish/marshal/base64.py +24 -9
- omlish/marshal/dataclasses.py +34 -28
- omlish/marshal/datetimes.py +74 -18
- omlish/marshal/enums.py +14 -8
- omlish/marshal/exceptions.py +11 -1
- omlish/marshal/factories.py +59 -74
- omlish/marshal/forbidden.py +35 -0
- omlish/marshal/global_.py +11 -4
- omlish/marshal/iterables.py +21 -24
- omlish/marshal/mappings.py +23 -26
- omlish/marshal/naming.py +4 -0
- omlish/marshal/numbers.py +51 -0
- omlish/marshal/objects.py +1 -0
- omlish/marshal/optionals.py +11 -12
- omlish/marshal/polymorphism.py +86 -21
- omlish/marshal/primitives.py +4 -5
- omlish/marshal/standard.py +13 -8
- omlish/marshal/uuids.py +4 -5
- omlish/matchfns.py +218 -0
- omlish/os.py +64 -0
- omlish/reflect/__init__.py +39 -0
- omlish/reflect/isinstance.py +38 -0
- omlish/reflect/ops.py +84 -0
- omlish/reflect/subst.py +110 -0
- omlish/reflect/types.py +275 -0
- omlish/secrets/__init__.py +23 -0
- omlish/secrets/crypto.py +132 -0
- omlish/secrets/marshal.py +70 -0
- omlish/secrets/openssl.py +207 -0
- omlish/secrets/passwords.py +120 -0
- omlish/secrets/secrets.py +299 -0
- omlish/secrets/subprocesses.py +42 -0
- omlish/sql/dbs.py +7 -6
- omlish/sql/duckdb.py +136 -0
- omlish/sql/exprs.py +12 -0
- omlish/sql/secrets.py +10 -0
- omlish/sql/sqlean.py +17 -0
- omlish/term.py +2 -2
- omlish/testing/pytest/__init__.py +3 -2
- omlish/testing/pytest/inject/harness.py +3 -3
- omlish/testing/pytest/marks.py +4 -7
- omlish/testing/pytest/plugins/__init__.py +1 -0
- omlish/testing/pytest/plugins/asyncs.py +136 -0
- omlish/testing/pytest/plugins/pydevd.py +1 -1
- omlish/testing/pytest/plugins/switches.py +54 -19
- omlish/text/glyphsplit.py +97 -0
- omlish-0.0.0.dev7.dist-info/METADATA +50 -0
- omlish-0.0.0.dev7.dist-info/RECORD +268 -0
- {omlish-0.0.0.dev5.dist-info → omlish-0.0.0.dev7.dist-info}/WHEEL +1 -1
- omlish/reflect.py +0 -355
- omlish-0.0.0.dev5.dist-info/METADATA +0 -34
- omlish-0.0.0.dev5.dist-info/RECORD +0 -212
- /omlish/{asyncs/futures.py → concurrent.py} +0 -0
- /omlish/{configs → formats}/props.py +0 -0
- {omlish-0.0.0.dev5.dist-info → omlish-0.0.0.dev7.dist-info}/LICENSE +0 -0
- {omlish-0.0.0.dev5.dist-info → omlish-0.0.0.dev7.dist-info}/top_level.txt +0 -0
omlish/inject/inspect.py
CHANGED
|
@@ -1,8 +1,18 @@
|
|
|
1
1
|
import typing as ta
|
|
2
2
|
|
|
3
|
+
from .. import lang
|
|
3
4
|
from .keys import Key
|
|
4
5
|
|
|
5
6
|
|
|
7
|
+
if ta.TYPE_CHECKING:
|
|
8
|
+
from .impl import inspect as _inspect
|
|
9
|
+
else:
|
|
10
|
+
_inspect = lang.proxy_import('.impl.inspect', __package__)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
T = ta.TypeVar('T')
|
|
14
|
+
|
|
15
|
+
|
|
6
16
|
class Kwarg(ta.NamedTuple):
|
|
7
17
|
name: str
|
|
8
18
|
key: Key
|
|
@@ -12,3 +22,11 @@ class Kwarg(ta.NamedTuple):
|
|
|
12
22
|
class KwargsTarget(ta.NamedTuple):
|
|
13
23
|
obj: ta.Any
|
|
14
24
|
kwargs: ta.Sequence[Kwarg]
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def tag(obj: T, **kwargs: ta.Any) -> T:
|
|
28
|
+
return _inspect.tag(obj, **kwargs)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def build_kwargs_target(obj: ta.Any, **kwargs: ta.Any) -> KwargsTarget:
|
|
32
|
+
return _inspect.build_kwargs_target(obj, **kwargs)
|
omlish/inject/keys.py
CHANGED
|
@@ -4,34 +4,28 @@ import typing as ta
|
|
|
4
4
|
from .. import dataclasses as dc
|
|
5
5
|
from .. import lang
|
|
6
6
|
from .. import reflect as rfl
|
|
7
|
+
from .types import Tag
|
|
7
8
|
|
|
8
9
|
|
|
9
10
|
T = ta.TypeVar('T')
|
|
10
11
|
|
|
11
12
|
|
|
12
|
-
##
|
|
13
|
-
|
|
14
|
-
|
|
15
13
|
@dc.dataclass(frozen=True)
|
|
16
14
|
@dc.extra_params(cache_hash=True)
|
|
17
15
|
class Key(lang.Final, ta.Generic[T]):
|
|
18
16
|
ty: rfl.Type = dc.xfield(coerce=rfl.type_)
|
|
19
|
-
tag: ta.Any = dc.field(default=None, kw_only=True)
|
|
20
17
|
|
|
21
|
-
|
|
22
|
-
|
|
18
|
+
tag: ta.Any = dc.xfield(
|
|
19
|
+
default=None,
|
|
20
|
+
kw_only=True,
|
|
21
|
+
check=lambda o: not isinstance(o, Tag),
|
|
22
|
+
repr_fn=dc.opt_repr,
|
|
23
|
+
)
|
|
23
24
|
|
|
24
25
|
|
|
25
26
|
def as_key(o: ta.Any) -> Key:
|
|
26
|
-
if o is inspect.Parameter.empty:
|
|
27
|
+
if o is None or o is inspect.Parameter.empty:
|
|
27
28
|
raise TypeError(o)
|
|
28
29
|
if isinstance(o, Key):
|
|
29
30
|
return o
|
|
30
31
|
return Key(rfl.type_(o))
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
##
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
def tag(o: ta.Any, t: ta.Any) -> Key:
|
|
37
|
-
return dc.replace(as_key(o), tag=t)
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import typing as ta
|
|
2
|
+
|
|
3
|
+
from .. import dataclasses as dc
|
|
4
|
+
from .. import lang
|
|
5
|
+
from .bindings import Binding
|
|
6
|
+
from .elements import Element
|
|
7
|
+
from .injector import Injector
|
|
8
|
+
from .keys import Key
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
ProvisionListener: ta.TypeAlias = ta.Callable[[
|
|
12
|
+
Injector,
|
|
13
|
+
Key,
|
|
14
|
+
Binding,
|
|
15
|
+
ta.Callable[[], ta.Any],
|
|
16
|
+
], ta.Callable[[], ta.Any]]
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@dc.dataclass(frozen=True)
|
|
20
|
+
@dc.extra_params(cache_hash=True)
|
|
21
|
+
class ProvisionListenerBinding(Element, lang.Final):
|
|
22
|
+
listener: ProvisionListener
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def bind_provision_listener(l: ProvisionListener) -> Element:
|
|
26
|
+
return ProvisionListenerBinding(l)
|
omlish/inject/managed.py
CHANGED
|
@@ -5,20 +5,86 @@ TODO:
|
|
|
5
5
|
import contextlib
|
|
6
6
|
import typing as ta
|
|
7
7
|
|
|
8
|
-
from
|
|
9
|
-
from .
|
|
10
|
-
from .elements import
|
|
8
|
+
from .. import lang
|
|
9
|
+
from .binder import bind
|
|
10
|
+
from .elements import Elemental
|
|
11
|
+
from .impl.inspect import build_kwargs_target
|
|
11
12
|
from .injector import Injector
|
|
12
13
|
from .injector import create_injector
|
|
13
|
-
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
if ta.TYPE_CHECKING:
|
|
17
|
+
from .. import asyncs as _asyncs
|
|
18
|
+
else:
|
|
19
|
+
_asyncs = lang.proxy_import('..asyncs', __package__)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
T = ta.TypeVar('T')
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
##
|
|
14
26
|
|
|
15
27
|
|
|
16
28
|
@contextlib.contextmanager
|
|
17
|
-
def create_managed_injector(
|
|
18
|
-
i = create_injector(
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
))
|
|
29
|
+
def create_managed_injector(*args: Elemental) -> ta.Generator[Injector, None, None]:
|
|
30
|
+
i = create_injector(
|
|
31
|
+
bind(contextlib.ExitStack, singleton=True, eager=True),
|
|
32
|
+
*args,
|
|
33
|
+
)
|
|
23
34
|
with i[contextlib.ExitStack]:
|
|
24
35
|
yield i
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def make_managed_provider(
|
|
39
|
+
fac: ta.Callable[..., T],
|
|
40
|
+
*fns: ta.Callable[[T], ta.ContextManager[T]],
|
|
41
|
+
) -> ta.Callable[..., T]:
|
|
42
|
+
kt = build_kwargs_target(fac)
|
|
43
|
+
|
|
44
|
+
def _provide(
|
|
45
|
+
i: Injector,
|
|
46
|
+
es: contextlib.ExitStack,
|
|
47
|
+
):
|
|
48
|
+
obj = i.inject(kt)
|
|
49
|
+
if not fns:
|
|
50
|
+
obj = es.enter_context(obj)
|
|
51
|
+
else:
|
|
52
|
+
for fn in fns:
|
|
53
|
+
es.enter_context(fn(obj))
|
|
54
|
+
return obj
|
|
55
|
+
|
|
56
|
+
return _provide
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
##
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
@contextlib.asynccontextmanager
|
|
63
|
+
async def create_async_managed_injector(*args: Elemental) -> ta.AsyncGenerator[Injector, None]:
|
|
64
|
+
i = await _asyncs.s_to_a(create_injector)(
|
|
65
|
+
bind(contextlib.AsyncExitStack, singleton=True, eager=True),
|
|
66
|
+
*args,
|
|
67
|
+
)
|
|
68
|
+
async with i[contextlib.AsyncExitStack]:
|
|
69
|
+
yield i
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def make_async_managed_provider(
|
|
73
|
+
fac: ta.Callable[..., T],
|
|
74
|
+
*fns: ta.Callable[[T], ta.AsyncContextManager[T]],
|
|
75
|
+
) -> ta.Callable[..., T]:
|
|
76
|
+
kt = build_kwargs_target(fac)
|
|
77
|
+
|
|
78
|
+
def _provide(
|
|
79
|
+
i: Injector,
|
|
80
|
+
aes: contextlib.AsyncExitStack,
|
|
81
|
+
):
|
|
82
|
+
obj = i.inject(kt)
|
|
83
|
+
if not fns:
|
|
84
|
+
obj = _asyncs.a_to_s(aes.enter_async_context)(obj)
|
|
85
|
+
else:
|
|
86
|
+
for fn in fns:
|
|
87
|
+
_asyncs.a_to_s(aes.enter_async_context)(fn(obj))
|
|
88
|
+
return obj
|
|
89
|
+
|
|
90
|
+
return _provide
|
omlish/inject/multis.py
CHANGED
|
@@ -5,16 +5,23 @@ TODO:
|
|
|
5
5
|
import collections.abc
|
|
6
6
|
import typing as ta
|
|
7
7
|
|
|
8
|
+
from .. import check
|
|
8
9
|
from .. import dataclasses as dc
|
|
9
10
|
from .. import lang
|
|
10
11
|
from .. import reflect as rfl
|
|
11
12
|
from .bindings import Binding
|
|
12
13
|
from .elements import Element
|
|
14
|
+
from .elements import ElementGenerator
|
|
13
15
|
from .keys import Key
|
|
14
16
|
from .keys import as_key
|
|
15
17
|
from .providers import Provider
|
|
16
18
|
|
|
17
19
|
|
|
20
|
+
T = ta.TypeVar('T')
|
|
21
|
+
K = ta.TypeVar('K')
|
|
22
|
+
V = ta.TypeVar('V')
|
|
23
|
+
|
|
24
|
+
|
|
18
25
|
##
|
|
19
26
|
|
|
20
27
|
|
|
@@ -26,21 +33,14 @@ def _check_set_multi_key(mk: Key) -> bool:
|
|
|
26
33
|
@dc.extra_params(cache_hash=True)
|
|
27
34
|
class SetBinding(Element, lang.Final):
|
|
28
35
|
multi_key: Key = dc.xfield(check=_check_set_multi_key)
|
|
29
|
-
dst: Key = dc.xfield()
|
|
36
|
+
dst: Key = dc.xfield(coerce=check.of_isinstance(Key))
|
|
30
37
|
|
|
31
38
|
|
|
32
|
-
@dc.dataclass(frozen=True
|
|
39
|
+
@dc.dataclass(frozen=True)
|
|
40
|
+
@dc.extra_params(cache_hash=True)
|
|
33
41
|
class SetProvider(Provider):
|
|
34
42
|
multi_key: Key = dc.xfield(check=_check_set_multi_key)
|
|
35
43
|
|
|
36
|
-
def provided_ty(self) -> rfl.Type | None:
|
|
37
|
-
return self.multi_key.ty
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
def bind_set_provider(multi_key: ta.Any) -> Element:
|
|
41
|
-
multi_key = as_key(multi_key)
|
|
42
|
-
return Binding(multi_key, SetProvider(multi_key))
|
|
43
|
-
|
|
44
44
|
|
|
45
45
|
##
|
|
46
46
|
|
|
@@ -53,18 +53,68 @@ def _check_map_multi_key(mk: Key) -> bool:
|
|
|
53
53
|
@dc.extra_params(cache_hash=True)
|
|
54
54
|
class MapBinding(Element, lang.Final):
|
|
55
55
|
multi_key: Key = dc.xfield(check=_check_map_multi_key)
|
|
56
|
-
map_key: ta.Any = dc.xfield(
|
|
57
|
-
dst: Key = dc.xfield(())
|
|
56
|
+
map_key: ta.Any = dc.xfield()
|
|
57
|
+
dst: Key = dc.xfield(coerce=check.of_isinstance(Key))
|
|
58
58
|
|
|
59
59
|
|
|
60
|
-
@dc.dataclass(frozen=True
|
|
60
|
+
@dc.dataclass(frozen=True)
|
|
61
|
+
@dc.extra_params(cache_hash=True)
|
|
61
62
|
class MapProvider(Provider):
|
|
62
63
|
multi_key: Key = dc.xfield(check=_check_map_multi_key)
|
|
63
64
|
|
|
64
|
-
|
|
65
|
-
|
|
65
|
+
|
|
66
|
+
##
|
|
66
67
|
|
|
67
68
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
69
|
+
class SetBinder(ElementGenerator, ta.Generic[T]):
|
|
70
|
+
def __init__(self, *, tag: ta.Any = None) -> None:
|
|
71
|
+
super().__init__()
|
|
72
|
+
self._tag: ta.Any = tag
|
|
73
|
+
self._sbs: list[SetBinding] = []
|
|
74
|
+
|
|
75
|
+
@lang.cached_property
|
|
76
|
+
def _multi_key(self) -> Key:
|
|
77
|
+
oty = rfl.type_(rfl.get_orig_class(self))
|
|
78
|
+
ety = check.single(check.isinstance(oty, rfl.Generic).args)
|
|
79
|
+
return Key(ta.AbstractSet[ety], tag=self._tag) # type: ignore
|
|
80
|
+
|
|
81
|
+
@lang.cached_property
|
|
82
|
+
def _set_provider_binding(self) -> Element:
|
|
83
|
+
return Binding(self._multi_key, SetProvider(self._multi_key))
|
|
84
|
+
|
|
85
|
+
def bind(self, *keys: ta.Any) -> ta.Self:
|
|
86
|
+
if not isinstance(self, SetBinder):
|
|
87
|
+
raise TypeError
|
|
88
|
+
self._sbs.extend(SetBinding(self._multi_key, as_key(k)) for k in keys)
|
|
89
|
+
return self # type: ignore
|
|
90
|
+
|
|
91
|
+
def __iter__(self) -> ta.Iterator[Element]:
|
|
92
|
+
yield self._set_provider_binding
|
|
93
|
+
yield from self._sbs
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
class MapBinder(ElementGenerator, ta.Generic[K, V]):
|
|
97
|
+
def __init__(self, *, tag: ta.Any = None) -> None:
|
|
98
|
+
super().__init__()
|
|
99
|
+
self._tag: ta.Any = tag
|
|
100
|
+
self._mbs: list[MapBinding] = []
|
|
101
|
+
|
|
102
|
+
@lang.cached_property
|
|
103
|
+
def _multi_key(self) -> Key:
|
|
104
|
+
oty = rfl.type_(rfl.get_orig_class(self))
|
|
105
|
+
kty, vty = check.isinstance(oty, rfl.Generic).args
|
|
106
|
+
return Key(ta.Mapping[kty, vty], tag=self._tag) # type: ignore
|
|
107
|
+
|
|
108
|
+
@lang.cached_property
|
|
109
|
+
def _map_provider_binding(self) -> Element:
|
|
110
|
+
return Binding(self._multi_key, MapProvider(self._multi_key))
|
|
111
|
+
|
|
112
|
+
def bind(self, map_key: K, map_value_key: ta.Any) -> ta.Self:
|
|
113
|
+
if not isinstance(self, MapBinder):
|
|
114
|
+
raise TypeError
|
|
115
|
+
self._mbs.append(MapBinding(self._multi_key, map_key, as_key(map_value_key)))
|
|
116
|
+
return self # type: ignore
|
|
117
|
+
|
|
118
|
+
def __iter__(self) -> ta.Iterator[Element]:
|
|
119
|
+
yield self._map_provider_binding
|
|
120
|
+
yield from self._mbs
|
omlish/inject/origins.py
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import abc
|
|
2
|
+
import typing as ta
|
|
3
|
+
|
|
4
|
+
from .. import dataclasses as dc
|
|
5
|
+
from .. import lang
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
T = ta.TypeVar('T')
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@dc.dataclass(frozen=True)
|
|
12
|
+
@dc.extra_params(cache_hash=True)
|
|
13
|
+
class Origin:
|
|
14
|
+
lst: ta.Sequence[str]
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@dc.dataclass(frozen=True)
|
|
18
|
+
@dc.extra_params(cache_hash=True)
|
|
19
|
+
class Origins:
|
|
20
|
+
lst: ta.Sequence[Origin]
|
|
21
|
+
|
|
22
|
+
def __iter__(self) -> ta.Iterator[Origin]:
|
|
23
|
+
yield from self.lst
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class HasOrigins(lang.Abstract):
|
|
27
|
+
@property
|
|
28
|
+
@abc.abstractmethod
|
|
29
|
+
def origins(self) -> Origins:
|
|
30
|
+
raise NotImplementedError
|
omlish/inject/overrides.py
CHANGED
|
@@ -1,18 +1,19 @@
|
|
|
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
|
-
from .binder import bind
|
|
6
6
|
from .elements import Element
|
|
7
7
|
from .elements import Elements
|
|
8
|
+
from .elements import as_elements
|
|
8
9
|
|
|
9
10
|
|
|
10
11
|
@dc.dataclass(frozen=True)
|
|
11
12
|
@dc.extra_params(cache_hash=True)
|
|
12
13
|
class Overrides(Element, lang.Final):
|
|
13
|
-
ovr: Elements
|
|
14
|
-
src: Elements
|
|
14
|
+
ovr: Elements = dc.xfield(coerce=check.of_isinstance(Elements))
|
|
15
|
+
src: Elements = dc.xfield(coerce=check.of_isinstance(Elements))
|
|
15
16
|
|
|
16
17
|
|
|
17
18
|
def override(ovr: ta.Any, *a: ta.Any) -> Element:
|
|
18
|
-
return Overrides(
|
|
19
|
+
return Overrides(as_elements(ovr), as_elements(*a))
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import typing as ta
|
|
2
|
-
|
|
3
1
|
from .. import check
|
|
4
2
|
from .. import dataclasses as dc
|
|
5
3
|
from .. import lang
|
|
6
4
|
from .elements import Element
|
|
5
|
+
from .elements import Elemental
|
|
7
6
|
from .elements import Elements
|
|
7
|
+
from .elements import as_elements
|
|
8
8
|
from .keys import Key
|
|
9
9
|
from .keys import as_key
|
|
10
10
|
|
|
@@ -12,18 +12,14 @@ from .keys import as_key
|
|
|
12
12
|
@dc.dataclass(frozen=True)
|
|
13
13
|
@dc.extra_params(cache_hash=True)
|
|
14
14
|
class Expose(Element, lang.Final):
|
|
15
|
-
key: Key
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
def expose(k: ta.Any) -> Element:
|
|
19
|
-
return Expose(as_key(k))
|
|
15
|
+
key: Key = dc.xfield(coerce=as_key)
|
|
20
16
|
|
|
21
17
|
|
|
22
18
|
@dc.dataclass(frozen=True)
|
|
23
19
|
@dc.extra_params(cache_hash=True)
|
|
24
20
|
class Private(Element, lang.Final):
|
|
25
|
-
elements: Elements
|
|
21
|
+
elements: Elements = dc.xfield(coerce=check.of_isinstance(Elements))
|
|
26
22
|
|
|
27
23
|
|
|
28
|
-
def private(
|
|
29
|
-
return Private(
|
|
24
|
+
def private(*args: Elemental) -> Private:
|
|
25
|
+
return Private(as_elements(*args))
|
omlish/inject/providers.py
CHANGED
|
@@ -1,111 +1,38 @@
|
|
|
1
|
-
import abc
|
|
2
1
|
import typing as ta
|
|
3
2
|
|
|
4
3
|
from .. import check
|
|
5
4
|
from .. import dataclasses as dc
|
|
6
5
|
from .. import lang
|
|
7
|
-
from .. import reflect as rfl
|
|
8
|
-
from .elements import Element
|
|
9
|
-
from .elements import Elements
|
|
10
|
-
from .impl.inspect import signature
|
|
11
6
|
from .keys import Key
|
|
12
|
-
from .keys import as_key
|
|
13
7
|
|
|
14
8
|
|
|
15
9
|
class _Missing(lang.NotInstantiable):
|
|
16
10
|
pass
|
|
17
11
|
|
|
18
12
|
|
|
19
|
-
##
|
|
20
|
-
|
|
21
|
-
|
|
22
13
|
class Provider(lang.Abstract):
|
|
23
|
-
|
|
24
|
-
def provided_ty(self) -> rfl.Type | None:
|
|
25
|
-
raise NotImplementedError
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
##
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
def as_provider(o: ta.Any) -> Provider:
|
|
32
|
-
check.not_isinstance(o, (Element, Elements))
|
|
33
|
-
if isinstance(o, Provider):
|
|
34
|
-
return o
|
|
35
|
-
if isinstance(o, Key):
|
|
36
|
-
return link(o)
|
|
37
|
-
if isinstance(o, type):
|
|
38
|
-
return ctor(o)
|
|
39
|
-
if callable(o):
|
|
40
|
-
return fn(o)
|
|
41
|
-
return const(o)
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
##
|
|
14
|
+
pass
|
|
45
15
|
|
|
46
16
|
|
|
47
|
-
@dc.dataclass(frozen=True
|
|
17
|
+
@dc.dataclass(frozen=True)
|
|
18
|
+
@dc.extra_params(cache_hash=True)
|
|
48
19
|
class FnProvider(Provider):
|
|
49
|
-
fn: ta.Any
|
|
50
|
-
ty: rfl.Type | None = None
|
|
51
|
-
|
|
52
|
-
def provided_ty(self) -> rfl.Type | None:
|
|
53
|
-
return self.ty
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
def fn(fn: ta.Any, ty: rfl.Type | None = _Missing) -> Provider:
|
|
57
|
-
check.not_isinstance(fn, type)
|
|
58
|
-
check.callable(fn)
|
|
59
|
-
if ty is _Missing:
|
|
60
|
-
sig = signature(fn)
|
|
61
|
-
ty = check.isinstance(sig.return_annotation, type)
|
|
62
|
-
return FnProvider(fn, ty)
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
##
|
|
20
|
+
fn: ta.Any = dc.xfield(check=callable)
|
|
66
21
|
|
|
67
22
|
|
|
68
|
-
@dc.dataclass(frozen=True
|
|
23
|
+
@dc.dataclass(frozen=True)
|
|
24
|
+
@dc.extra_params(cache_hash=True)
|
|
69
25
|
class CtorProvider(Provider):
|
|
70
|
-
ty: type
|
|
26
|
+
ty: type = dc.xfield(coerce=check.of_isinstance(type))
|
|
71
27
|
|
|
72
|
-
def provided_ty(self) -> type:
|
|
73
|
-
return self.ty
|
|
74
28
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
check.isinstance(ty, type)
|
|
78
|
-
return CtorProvider(ty)
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
##
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
@dc.dataclass(frozen=True, eq=False)
|
|
29
|
+
@dc.dataclass(frozen=True)
|
|
30
|
+
@dc.extra_params(cache_hash=True)
|
|
85
31
|
class ConstProvider(Provider):
|
|
86
32
|
v: ta.Any
|
|
87
|
-
ty: rfl.Type | None = None
|
|
88
|
-
|
|
89
|
-
def provided_ty(self) -> rfl.Type | None:
|
|
90
|
-
return self.ty
|
|
91
|
-
|
|
92
33
|
|
|
93
|
-
def const(v: ta.Any, ty: rfl.Type | None = _Missing) -> Provider:
|
|
94
|
-
if ty is _Missing:
|
|
95
|
-
ty = type(v)
|
|
96
|
-
return ConstProvider(v, ty)
|
|
97
34
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
@dc.dataclass(frozen=True, eq=False)
|
|
35
|
+
@dc.dataclass(frozen=True)
|
|
36
|
+
@dc.extra_params(cache_hash=True)
|
|
103
37
|
class LinkProvider(Provider):
|
|
104
|
-
k: Key
|
|
105
|
-
|
|
106
|
-
def provided_ty(self) -> rfl.Type | None:
|
|
107
|
-
return None
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
def link(k: ta.Any) -> Provider:
|
|
111
|
-
return LinkProvider(as_key(k))
|
|
38
|
+
k: Key = dc.xfield(coerce=check.of_isinstance(Key))
|
omlish/inject/scopes.py
CHANGED
|
@@ -7,7 +7,6 @@ from .. import dataclasses as dc
|
|
|
7
7
|
from .. import lang
|
|
8
8
|
from .. import reflect as rfl
|
|
9
9
|
from .bindings import Binding
|
|
10
|
-
from .bindings import as_binding
|
|
11
10
|
from .elements import Element
|
|
12
11
|
from .keys import Key
|
|
13
12
|
from .keys import as_key
|
|
@@ -24,6 +23,9 @@ else:
|
|
|
24
23
|
##
|
|
25
24
|
|
|
26
25
|
|
|
26
|
+
SCOPE_ALIASES: dict[str, Scope] = {}
|
|
27
|
+
|
|
28
|
+
|
|
27
29
|
@dc.dataclass(frozen=True)
|
|
28
30
|
@dc.extra_params(cache_hash=True)
|
|
29
31
|
class ScopeBinding(Element, lang.Final):
|
|
@@ -34,22 +36,26 @@ def bind_scope(sc: Scope) -> Element:
|
|
|
34
36
|
return ScopeBinding(sc)
|
|
35
37
|
|
|
36
38
|
|
|
37
|
-
|
|
38
|
-
return dc.replace(as_binding(b), scope=check.isinstance(sc, Scope))
|
|
39
|
+
##
|
|
39
40
|
|
|
40
41
|
|
|
41
42
|
class Singleton(Scope, lang.Singleton, lang.Final):
|
|
42
43
|
pass
|
|
43
44
|
|
|
44
45
|
|
|
45
|
-
|
|
46
|
-
|
|
46
|
+
SCOPE_ALIASES['singleton'] = Singleton()
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
##
|
|
47
50
|
|
|
48
51
|
|
|
49
52
|
class Thread(Scope, lang.Singleton, lang.Final):
|
|
50
53
|
pass
|
|
51
54
|
|
|
52
55
|
|
|
56
|
+
SCOPE_ALIASES['thread'] = Thread()
|
|
57
|
+
|
|
58
|
+
|
|
53
59
|
##
|
|
54
60
|
|
|
55
61
|
|
|
@@ -64,7 +70,8 @@ class SeededScope(Scope, lang.Final):
|
|
|
64
70
|
raise NotImplementedError
|
|
65
71
|
|
|
66
72
|
|
|
67
|
-
@dc.dataclass(frozen=True
|
|
73
|
+
@dc.dataclass(frozen=True)
|
|
74
|
+
@dc.extra_params(cache_hash=True)
|
|
68
75
|
class ScopeSeededProvider(Provider):
|
|
69
76
|
ss: SeededScope = dc.xfield(coerce=check.of_isinstance(SeededScope))
|
|
70
77
|
key: Key = dc.xfield(coerce=check.of_isinstance(Key))
|
omlish/inject/types.py
CHANGED
omlish/inject/utils.py
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import typing as ta
|
|
2
|
+
|
|
3
|
+
from .. import dataclasses as dc
|
|
4
|
+
from .. import lang
|
|
5
|
+
from .impl.origins import HasOriginsImpl
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
T = ta.TypeVar('T')
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@dc.dataclass(frozen=True, eq=False)
|
|
12
|
+
class ConstFn(HasOriginsImpl, lang.Final, ta.Generic[T]):
|
|
13
|
+
"""An origin tracking provider function for a constant value. Equivalent to `lambda: v` but transparent."""
|
|
14
|
+
|
|
15
|
+
v: T
|
|
16
|
+
|
|
17
|
+
def __call__(self) -> T:
|
|
18
|
+
return self.v
|