omlish 0.0.0.dev4__py3-none-any.whl → 0.0.0.dev6__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 +1 -1
- omlish/__init__.py +1 -1
- omlish/asyncs/__init__.py +10 -4
- omlish/asyncs/anyio.py +142 -12
- omlish/asyncs/asyncio.py +23 -0
- omlish/asyncs/asyncs.py +9 -6
- omlish/asyncs/bridge.py +316 -0
- omlish/asyncs/flavors.py +27 -1
- omlish/asyncs/trio_asyncio.py +28 -18
- omlish/c3.py +1 -1
- omlish/cached.py +1 -2
- omlish/collections/__init__.py +5 -1
- omlish/collections/cache/impl.py +1 -1
- omlish/collections/identity.py +7 -0
- omlish/collections/indexed.py +1 -1
- omlish/collections/utils.py +38 -6
- omlish/configs/__init__.py +5 -0
- omlish/configs/classes.py +53 -0
- omlish/configs/strings.py +94 -0
- omlish/dataclasses/__init__.py +9 -0
- omlish/dataclasses/impl/api.py +1 -1
- omlish/dataclasses/impl/as_.py +1 -1
- omlish/dataclasses/impl/copy.py +30 -0
- omlish/dataclasses/impl/exceptions.py +6 -0
- omlish/dataclasses/impl/fields.py +25 -25
- omlish/dataclasses/impl/init.py +5 -3
- omlish/dataclasses/impl/main.py +3 -0
- omlish/dataclasses/impl/metaclass.py +6 -1
- omlish/dataclasses/impl/order.py +1 -1
- omlish/dataclasses/impl/reflect.py +15 -2
- omlish/dataclasses/utils.py +44 -0
- omlish/defs.py +1 -1
- omlish/diag/__init__.py +4 -0
- omlish/diag/procfs.py +31 -3
- omlish/diag/procstats.py +32 -0
- omlish/{testing → diag}/pydevd.py +35 -0
- omlish/diag/replserver/console.py +3 -3
- omlish/diag/replserver/server.py +6 -5
- omlish/diag/threads.py +86 -0
- omlish/dispatch/_dispatch2.py +65 -0
- omlish/dispatch/_dispatch3.py +104 -0
- omlish/docker.py +20 -1
- omlish/fnpairs.py +37 -18
- omlish/graphs/dags.py +113 -0
- omlish/graphs/domination.py +268 -0
- omlish/graphs/trees.py +2 -2
- omlish/http/__init__.py +25 -0
- omlish/http/asgi.py +132 -0
- omlish/http/collections.py +15 -0
- omlish/http/consts.py +47 -5
- omlish/http/cookies.py +194 -0
- omlish/http/dates.py +70 -0
- omlish/http/encodings.py +6 -0
- omlish/http/json.py +273 -0
- omlish/http/sessions.py +204 -0
- omlish/inject/__init__.py +51 -17
- omlish/inject/binder.py +185 -5
- omlish/inject/bindings.py +3 -36
- omlish/inject/eagers.py +2 -8
- omlish/inject/elements.py +30 -9
- omlish/inject/exceptions.py +3 -3
- omlish/inject/impl/elements.py +65 -31
- omlish/inject/impl/injector.py +20 -2
- omlish/inject/impl/inspect.py +33 -5
- omlish/inject/impl/multis.py +74 -0
- omlish/inject/impl/origins.py +75 -0
- omlish/inject/impl/{private.py → privates.py} +2 -2
- omlish/inject/impl/providers.py +19 -39
- omlish/inject/{proxy.py → impl/proxy.py} +2 -2
- omlish/inject/impl/scopes.py +7 -2
- omlish/inject/injector.py +9 -4
- omlish/inject/inspect.py +18 -0
- omlish/inject/keys.py +11 -23
- omlish/inject/listeners.py +26 -0
- omlish/inject/managed.py +76 -10
- omlish/inject/multis.py +120 -0
- omlish/inject/origins.py +27 -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 +20 -9
- omlish/inject/types.py +2 -8
- omlish/iterators.py +13 -0
- omlish/lang/__init__.py +12 -2
- omlish/lang/cached.py +2 -2
- omlish/lang/classes/restrict.py +3 -2
- omlish/lang/classes/simple.py +18 -8
- omlish/lang/classes/virtual.py +2 -2
- omlish/lang/contextmanagers.py +75 -2
- omlish/lang/datetimes.py +6 -5
- omlish/lang/descriptors.py +131 -0
- omlish/lang/functions.py +18 -28
- omlish/lang/imports.py +11 -2
- omlish/lang/iterables.py +20 -1
- omlish/lang/typing.py +6 -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/logs/formatters.py +1 -1
- omlish/logs/utils.py +1 -1
- omlish/marshal/__init__.py +4 -0
- omlish/marshal/datetimes.py +1 -1
- omlish/marshal/naming.py +4 -0
- omlish/marshal/objects.py +1 -0
- omlish/marshal/polymorphism.py +4 -4
- omlish/reflect.py +139 -18
- omlish/secrets/__init__.py +7 -0
- omlish/secrets/marshal.py +41 -0
- omlish/secrets/passwords.py +120 -0
- omlish/secrets/secrets.py +47 -0
- omlish/serde/__init__.py +0 -0
- omlish/serde/dotenv.py +574 -0
- omlish/{json.py → serde/json.py} +4 -2
- omlish/serde/props.py +604 -0
- omlish/serde/yaml.py +223 -0
- omlish/sql/dbs.py +1 -1
- omlish/sql/duckdb.py +136 -0
- omlish/sql/sqlean.py +17 -0
- omlish/sync.py +70 -0
- omlish/term.py +7 -2
- omlish/testing/pytest/__init__.py +8 -2
- omlish/testing/pytest/helpers.py +0 -24
- omlish/testing/pytest/inject/harness.py +4 -4
- omlish/testing/pytest/marks.py +45 -0
- omlish/testing/pytest/plugins/__init__.py +3 -0
- omlish/testing/pytest/plugins/asyncs.py +136 -0
- omlish/testing/pytest/plugins/managermarks.py +60 -0
- omlish/testing/pytest/plugins/pydevd.py +1 -1
- omlish/testing/testing.py +10 -0
- omlish/text/delimit.py +4 -0
- omlish/text/glyphsplit.py +92 -0
- {omlish-0.0.0.dev4.dist-info → omlish-0.0.0.dev6.dist-info}/METADATA +1 -1
- omlish-0.0.0.dev6.dist-info/RECORD +240 -0
- {omlish-0.0.0.dev4.dist-info → omlish-0.0.0.dev6.dist-info}/WHEEL +1 -1
- omlish/configs/props.py +0 -64
- omlish-0.0.0.dev4.dist-info/RECORD +0 -195
- {omlish-0.0.0.dev4.dist-info → omlish-0.0.0.dev6.dist-info}/LICENSE +0 -0
- {omlish-0.0.0.dev4.dist-info → omlish-0.0.0.dev6.dist-info}/top_level.txt +0 -0
omlish/inject/keys.py
CHANGED
|
@@ -3,41 +3,29 @@ import typing as ta
|
|
|
3
3
|
|
|
4
4
|
from .. import dataclasses as dc
|
|
5
5
|
from .. import lang
|
|
6
|
+
from .. import reflect as rfl
|
|
7
|
+
from .types import Tag
|
|
6
8
|
|
|
7
9
|
|
|
8
10
|
T = ta.TypeVar('T')
|
|
9
11
|
|
|
10
12
|
|
|
11
|
-
##
|
|
12
|
-
|
|
13
|
-
|
|
14
13
|
@dc.dataclass(frozen=True)
|
|
15
14
|
@dc.extra_params(cache_hash=True)
|
|
16
15
|
class Key(lang.Final, ta.Generic[T]):
|
|
17
|
-
|
|
18
|
-
tag: ta.Any = dc.field(default=None, kw_only=True)
|
|
19
|
-
multi: bool = dc.field(default=False, kw_only=True)
|
|
20
|
-
|
|
16
|
+
ty: rfl.Type = dc.xfield(coerce=rfl.type_)
|
|
21
17
|
|
|
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(o)
|
|
32
|
-
raise TypeError(o)
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
##
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
def multi(o: ta.Any) -> Key:
|
|
39
|
-
return dc.replace(as_key(o), multi=True)
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
def tag(o: ta.Any, t: ta.Any) -> Key:
|
|
43
|
-
return dc.replace(as_key(o), tag=t)
|
|
31
|
+
return Key(rfl.type_(o))
|
|
@@ -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
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
"""
|
|
2
|
+
TODO:
|
|
3
|
+
- scopes
|
|
4
|
+
"""
|
|
5
|
+
import collections.abc
|
|
6
|
+
import typing as ta
|
|
7
|
+
|
|
8
|
+
from .. import check
|
|
9
|
+
from .. import dataclasses as dc
|
|
10
|
+
from .. import lang
|
|
11
|
+
from .. import reflect as rfl
|
|
12
|
+
from .bindings import Binding
|
|
13
|
+
from .elements import Element
|
|
14
|
+
from .elements import ElementGenerator
|
|
15
|
+
from .keys import Key
|
|
16
|
+
from .keys import as_key
|
|
17
|
+
from .providers import Provider
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
T = ta.TypeVar('T')
|
|
21
|
+
K = ta.TypeVar('K')
|
|
22
|
+
V = ta.TypeVar('V')
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
##
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def _check_set_multi_key(mk: Key) -> bool:
|
|
29
|
+
return rfl.get_concrete_type(mk.ty) is collections.abc.Set
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
@dc.dataclass(frozen=True)
|
|
33
|
+
@dc.extra_params(cache_hash=True)
|
|
34
|
+
class SetBinding(Element, lang.Final):
|
|
35
|
+
multi_key: Key = dc.xfield(check=_check_set_multi_key)
|
|
36
|
+
dst: Key = dc.xfield(coerce=check.of_isinstance(Key))
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
@dc.dataclass(frozen=True)
|
|
40
|
+
@dc.extra_params(cache_hash=True)
|
|
41
|
+
class SetProvider(Provider):
|
|
42
|
+
multi_key: Key = dc.xfield(check=_check_set_multi_key)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
##
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def _check_map_multi_key(mk: Key) -> bool:
|
|
49
|
+
return rfl.get_concrete_type(mk.ty) is collections.abc.Mapping
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
@dc.dataclass(frozen=True)
|
|
53
|
+
@dc.extra_params(cache_hash=True)
|
|
54
|
+
class MapBinding(Element, lang.Final):
|
|
55
|
+
multi_key: Key = dc.xfield(check=_check_map_multi_key)
|
|
56
|
+
map_key: ta.Any = dc.xfield()
|
|
57
|
+
dst: Key = dc.xfield(coerce=check.of_isinstance(Key))
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
@dc.dataclass(frozen=True)
|
|
61
|
+
@dc.extra_params(cache_hash=True)
|
|
62
|
+
class MapProvider(Provider):
|
|
63
|
+
multi_key: Key = dc.xfield(check=_check_map_multi_key)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
##
|
|
67
|
+
|
|
68
|
+
|
|
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,27 @@
|
|
|
1
|
+
import abc
|
|
2
|
+
import typing as ta
|
|
3
|
+
|
|
4
|
+
from .. import dataclasses as dc
|
|
5
|
+
from .. import lang
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@dc.dataclass(frozen=True)
|
|
9
|
+
@dc.extra_params(cache_hash=True)
|
|
10
|
+
class Origin:
|
|
11
|
+
lst: ta.Sequence[str]
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@dc.dataclass(frozen=True)
|
|
15
|
+
@dc.extra_params(cache_hash=True)
|
|
16
|
+
class Origins:
|
|
17
|
+
lst: ta.Sequence[Origin]
|
|
18
|
+
|
|
19
|
+
def __iter__(self) -> ta.Iterator[Origin]:
|
|
20
|
+
yield from self.lst
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class HasOrigins(lang.Abstract):
|
|
24
|
+
@property
|
|
25
|
+
@abc.abstractmethod
|
|
26
|
+
def origins(self) -> Origins:
|
|
27
|
+
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 .elements import Element
|
|
8
|
-
from .elements import Elements
|
|
9
|
-
from .impl.inspect import signature
|
|
10
6
|
from .keys import Key
|
|
11
|
-
from .keys import as_key
|
|
12
|
-
from .types import Cls
|
|
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_cls(self) -> Cls | 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
|
-
cls: Cls | None = None
|
|
51
|
-
|
|
52
|
-
def provided_cls(self) -> Cls | None:
|
|
53
|
-
return self.cls
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
def fn(fn: ta.Any, cls: Cls | None = _Missing) -> Provider:
|
|
57
|
-
check.not_isinstance(fn, type)
|
|
58
|
-
check.callable(fn)
|
|
59
|
-
if cls is _Missing:
|
|
60
|
-
sig = signature(fn)
|
|
61
|
-
cls = check.isinstance(sig.return_annotation, type)
|
|
62
|
-
return FnProvider(fn, cls)
|
|
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
|
-
|
|
26
|
+
ty: type = dc.xfield(coerce=check.of_isinstance(type))
|
|
71
27
|
|
|
72
|
-
def provided_cls(self) -> Cls:
|
|
73
|
-
return self.cls
|
|
74
28
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
check.isinstance(cls, type)
|
|
78
|
-
return CtorProvider(cls)
|
|
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
|
-
cls: Cls | None = None
|
|
88
|
-
|
|
89
|
-
def provided_cls(self) -> Cls | None:
|
|
90
|
-
return self.cls
|
|
91
|
-
|
|
92
33
|
|
|
93
|
-
def const(v: ta.Any, cls: Cls | None = _Missing) -> Provider:
|
|
94
|
-
if cls is _Missing:
|
|
95
|
-
cls = type(v)
|
|
96
|
-
return ConstProvider(v, cls)
|
|
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_cls(self) -> Cls | 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
|
@@ -5,21 +5,27 @@ import typing as ta
|
|
|
5
5
|
from .. import check
|
|
6
6
|
from .. import dataclasses as dc
|
|
7
7
|
from .. import lang
|
|
8
|
+
from .. import reflect as rfl
|
|
8
9
|
from .bindings import Binding
|
|
9
|
-
from .bindings import as_binding
|
|
10
10
|
from .elements import Element
|
|
11
11
|
from .keys import Key
|
|
12
12
|
from .keys import as_key
|
|
13
13
|
from .providers import Provider
|
|
14
|
-
from .types import Cls
|
|
15
14
|
from .types import Scope
|
|
16
15
|
|
|
16
|
+
|
|
17
17
|
if ta.TYPE_CHECKING:
|
|
18
18
|
from . import injector as injector_
|
|
19
19
|
else:
|
|
20
20
|
injector_ = lang.proxy_import('.injector', __package__)
|
|
21
21
|
|
|
22
22
|
|
|
23
|
+
##
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
SCOPE_ALIASES: dict[str, Scope] = {}
|
|
27
|
+
|
|
28
|
+
|
|
23
29
|
@dc.dataclass(frozen=True)
|
|
24
30
|
@dc.extra_params(cache_hash=True)
|
|
25
31
|
class ScopeBinding(Element, lang.Final):
|
|
@@ -30,22 +36,26 @@ def bind_scope(sc: Scope) -> Element:
|
|
|
30
36
|
return ScopeBinding(sc)
|
|
31
37
|
|
|
32
38
|
|
|
33
|
-
|
|
34
|
-
return dc.replace(as_binding(b), scope=check.isinstance(sc, Scope))
|
|
39
|
+
##
|
|
35
40
|
|
|
36
41
|
|
|
37
42
|
class Singleton(Scope, lang.Singleton, lang.Final):
|
|
38
43
|
pass
|
|
39
44
|
|
|
40
45
|
|
|
41
|
-
|
|
42
|
-
|
|
46
|
+
SCOPE_ALIASES['singleton'] = Singleton()
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
##
|
|
43
50
|
|
|
44
51
|
|
|
45
52
|
class Thread(Scope, lang.Singleton, lang.Final):
|
|
46
53
|
pass
|
|
47
54
|
|
|
48
55
|
|
|
56
|
+
SCOPE_ALIASES['thread'] = Thread()
|
|
57
|
+
|
|
58
|
+
|
|
49
59
|
##
|
|
50
60
|
|
|
51
61
|
|
|
@@ -60,13 +70,14 @@ class SeededScope(Scope, lang.Final):
|
|
|
60
70
|
raise NotImplementedError
|
|
61
71
|
|
|
62
72
|
|
|
63
|
-
@dc.dataclass(frozen=True
|
|
73
|
+
@dc.dataclass(frozen=True)
|
|
74
|
+
@dc.extra_params(cache_hash=True)
|
|
64
75
|
class ScopeSeededProvider(Provider):
|
|
65
76
|
ss: SeededScope = dc.xfield(coerce=check.of_isinstance(SeededScope))
|
|
66
77
|
key: Key = dc.xfield(coerce=check.of_isinstance(Key))
|
|
67
78
|
|
|
68
|
-
def
|
|
69
|
-
return self.key.
|
|
79
|
+
def provided_ty(self) -> rfl.Type | None:
|
|
80
|
+
return self.key.ty
|
|
70
81
|
|
|
71
82
|
|
|
72
83
|
def bind_scope_seed(ss: SeededScope, k: ta.Any) -> Element:
|
omlish/inject/types.py
CHANGED
omlish/iterators.py
CHANGED
|
@@ -218,3 +218,16 @@ def expand_indexed_pairs(
|
|
|
218
218
|
if idx < width_:
|
|
219
219
|
result[idx] = value
|
|
220
220
|
return result
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
##
|
|
224
|
+
# https://docs.python.org/3/library/itertools.html#itertools-recipes
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
def sliding_window(it: ta.Iterable[T], n: int) -> ta.Iterator[tuple[T, ...]]:
|
|
228
|
+
# sliding_window('ABCDEFG', 4) -> ABCD BCDE CDEF DEFG
|
|
229
|
+
iterator = iter(it)
|
|
230
|
+
window = collections.deque(itertools.islice(iterator, n - 1), maxlen=n)
|
|
231
|
+
for x in iterator:
|
|
232
|
+
window.append(x)
|
|
233
|
+
yield tuple(window)
|
omlish/lang/__init__.py
CHANGED
|
@@ -46,7 +46,9 @@ from .cmp import ( # noqa
|
|
|
46
46
|
)
|
|
47
47
|
|
|
48
48
|
from .contextmanagers import ( # noqa
|
|
49
|
+
AsyncContextManager,
|
|
49
50
|
ContextManaged,
|
|
51
|
+
ContextManager,
|
|
50
52
|
ContextWrapped,
|
|
51
53
|
DefaultLockable,
|
|
52
54
|
ExitStacked,
|
|
@@ -78,9 +80,13 @@ from .descriptors import ( # noqa
|
|
|
78
80
|
access_forbidden,
|
|
79
81
|
attr_property,
|
|
80
82
|
classonly,
|
|
83
|
+
decorator,
|
|
81
84
|
is_method_descriptor,
|
|
82
85
|
item_property,
|
|
86
|
+
unwrap_func,
|
|
87
|
+
unwrap_func_with_partials,
|
|
83
88
|
unwrap_method_descriptors,
|
|
89
|
+
update_wrapper_except_dict,
|
|
84
90
|
)
|
|
85
91
|
|
|
86
92
|
from .exceptions import ( # noqa
|
|
@@ -90,24 +96,26 @@ from .exceptions import ( # noqa
|
|
|
90
96
|
from .functions import ( # noqa
|
|
91
97
|
Args,
|
|
92
98
|
VoidError,
|
|
99
|
+
as_async,
|
|
93
100
|
constant,
|
|
94
101
|
finally_,
|
|
95
102
|
identity,
|
|
96
103
|
is_lambda,
|
|
97
104
|
is_none,
|
|
98
105
|
is_not_none,
|
|
106
|
+
isinstance_of,
|
|
107
|
+
issubclass_of,
|
|
99
108
|
maybe_call,
|
|
100
109
|
periodically,
|
|
101
110
|
raise_,
|
|
102
111
|
raising,
|
|
103
112
|
recurse,
|
|
104
113
|
try_,
|
|
105
|
-
unwrap_func,
|
|
106
|
-
unwrap_func_with_partials,
|
|
107
114
|
void,
|
|
108
115
|
)
|
|
109
116
|
|
|
110
117
|
from .imports import ( # noqa
|
|
118
|
+
can_import,
|
|
111
119
|
import_all,
|
|
112
120
|
import_module,
|
|
113
121
|
import_module_attr,
|
|
@@ -123,8 +131,10 @@ from .iterables import ( # noqa
|
|
|
123
131
|
asrange,
|
|
124
132
|
exhaust,
|
|
125
133
|
ilen,
|
|
134
|
+
itergen,
|
|
126
135
|
peek,
|
|
127
136
|
prodrange,
|
|
137
|
+
renumerate,
|
|
128
138
|
take,
|
|
129
139
|
)
|
|
130
140
|
|
omlish/lang/cached.py
CHANGED
|
@@ -11,8 +11,8 @@ import typing as ta
|
|
|
11
11
|
|
|
12
12
|
from .contextmanagers import DefaultLockable
|
|
13
13
|
from .contextmanagers import default_lock
|
|
14
|
-
from .
|
|
15
|
-
from .
|
|
14
|
+
from .descriptors import unwrap_func
|
|
15
|
+
from .descriptors import unwrap_func_with_partials
|
|
16
16
|
|
|
17
17
|
|
|
18
18
|
P = ta.ParamSpec('P')
|