omlish 0.0.0.dev4__py3-none-any.whl → 0.0.0.dev5__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 +1 -4
- omlish/asyncs/anyio.py +66 -0
- omlish/asyncs/flavors.py +27 -1
- omlish/asyncs/trio_asyncio.py +24 -18
- omlish/c3.py +1 -1
- omlish/cached.py +1 -2
- omlish/collections/__init__.py +4 -1
- omlish/collections/cache/impl.py +1 -1
- 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/dotenv.py +586 -0
- omlish/configs/props.py +589 -49
- omlish/dataclasses/impl/api.py +1 -1
- omlish/dataclasses/impl/as_.py +1 -1
- omlish/dataclasses/impl/fields.py +1 -0
- omlish/dataclasses/impl/init.py +1 -1
- omlish/dataclasses/impl/main.py +1 -0
- omlish/dataclasses/impl/metaclass.py +6 -1
- omlish/dataclasses/impl/order.py +1 -1
- omlish/dataclasses/impl/reflect.py +15 -2
- omlish/defs.py +1 -1
- omlish/diag/procfs.py +29 -1
- omlish/diag/procstats.py +32 -0
- omlish/diag/replserver/console.py +3 -3
- omlish/diag/replserver/server.py +6 -5
- omlish/diag/threads.py +86 -0
- omlish/docker.py +19 -0
- omlish/fnpairs.py +26 -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 +131 -0
- omlish/http/consts.py +31 -4
- 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 +197 -0
- omlish/inject/__init__.py +8 -2
- omlish/inject/bindings.py +3 -3
- omlish/inject/exceptions.py +3 -3
- omlish/inject/impl/elements.py +33 -24
- omlish/inject/impl/injector.py +1 -0
- omlish/inject/impl/multis.py +74 -0
- omlish/inject/impl/providers.py +19 -39
- omlish/inject/{proxy.py → impl/proxy.py} +2 -2
- omlish/inject/impl/scopes.py +1 -0
- omlish/inject/injector.py +1 -0
- omlish/inject/keys.py +3 -9
- omlish/inject/multis.py +70 -0
- omlish/inject/providers.py +23 -23
- omlish/inject/scopes.py +7 -3
- omlish/inject/types.py +0 -8
- omlish/iterators.py +13 -0
- omlish/json.py +2 -1
- omlish/lang/__init__.py +4 -0
- omlish/lang/classes/restrict.py +1 -1
- omlish/lang/classes/virtual.py +2 -2
- omlish/lang/contextmanagers.py +64 -0
- omlish/lang/datetimes.py +6 -5
- omlish/lang/functions.py +10 -0
- omlish/lang/imports.py +11 -2
- omlish/lang/typing.py +1 -0
- omlish/logs/utils.py +1 -1
- omlish/marshal/datetimes.py +1 -1
- omlish/reflect.py +8 -2
- omlish/sync.py +70 -0
- omlish/term.py +6 -1
- omlish/testing/pytest/__init__.py +5 -0
- omlish/testing/pytest/helpers.py +0 -24
- omlish/testing/pytest/inject/harness.py +1 -1
- omlish/testing/pytest/marks.py +48 -0
- omlish/testing/pytest/plugins/__init__.py +2 -0
- omlish/testing/pytest/plugins/managermarks.py +60 -0
- omlish/testing/testing.py +10 -0
- omlish/text/delimit.py +4 -0
- {omlish-0.0.0.dev4.dist-info → omlish-0.0.0.dev5.dist-info}/METADATA +1 -1
- {omlish-0.0.0.dev4.dist-info → omlish-0.0.0.dev5.dist-info}/RECORD +86 -69
- {omlish-0.0.0.dev4.dist-info → omlish-0.0.0.dev5.dist-info}/WHEEL +1 -1
- {omlish-0.0.0.dev4.dist-info → omlish-0.0.0.dev5.dist-info}/LICENSE +0 -0
- {omlish-0.0.0.dev4.dist-info → omlish-0.0.0.dev5.dist-info}/top_level.txt +0 -0
omlish/inject/impl/elements.py
CHANGED
|
@@ -10,6 +10,8 @@ Multi's + Scopes:
|
|
|
10
10
|
|
|
11
11
|
Element Types:
|
|
12
12
|
- Binding
|
|
13
|
+
- SetBinding
|
|
14
|
+
- MapBinding
|
|
13
15
|
- Eager
|
|
14
16
|
- Overrides
|
|
15
17
|
- Expose
|
|
@@ -27,16 +29,22 @@ from ..elements import Element
|
|
|
27
29
|
from ..elements import Elements
|
|
28
30
|
from ..exceptions import DuplicateKeyError
|
|
29
31
|
from ..keys import Key
|
|
32
|
+
from ..multis import MapBinding
|
|
33
|
+
from ..multis import MapProvider
|
|
34
|
+
from ..multis import SetBinding
|
|
35
|
+
from ..multis import SetProvider
|
|
30
36
|
from ..overrides import Overrides
|
|
31
37
|
from ..private import Expose
|
|
32
38
|
from ..private import Private
|
|
33
39
|
from ..scopes import ScopeBinding
|
|
34
40
|
from ..types import Scope
|
|
35
41
|
from .bindings import BindingImpl
|
|
36
|
-
from .
|
|
42
|
+
from .multis import make_multi_provider_impl
|
|
43
|
+
from .providers import ProviderImpl
|
|
37
44
|
from .providers import make_provider_impl
|
|
38
45
|
from .scopes import make_scope_impl
|
|
39
46
|
|
|
47
|
+
|
|
40
48
|
if ta.TYPE_CHECKING:
|
|
41
49
|
from . import private as private_
|
|
42
50
|
else:
|
|
@@ -92,10 +100,13 @@ class ElementCollection(lang.Final):
|
|
|
92
100
|
pi = self._get_private_info(e)
|
|
93
101
|
self._build_raw_element_multimap(pi.owner_elements(), out)
|
|
94
102
|
|
|
103
|
+
elif isinstance(e, (SetBinding, MapBinding)):
|
|
104
|
+
add(e.multi_key, e)
|
|
105
|
+
|
|
95
106
|
elif isinstance(e, Overrides):
|
|
96
107
|
ovr = self._build_raw_element_multimap(e.ovr)
|
|
97
108
|
src = self._build_raw_element_multimap(e.src)
|
|
98
|
-
for k, b in src.items():
|
|
109
|
+
for k, b in src.items(): # FIXME: merge None keys?
|
|
99
110
|
try:
|
|
100
111
|
bs = ovr[k]
|
|
101
112
|
except KeyError:
|
|
@@ -117,36 +128,34 @@ class ElementCollection(lang.Final):
|
|
|
117
128
|
|
|
118
129
|
##
|
|
119
130
|
|
|
120
|
-
def _make_binding_impls(self, e: Element) -> ta.Iterable[BindingImpl]:
|
|
121
|
-
if isinstance(e, Binding):
|
|
122
|
-
p = make_provider_impl(e.provider)
|
|
123
|
-
return (BindingImpl(e.key, p, e.scope, e),)
|
|
124
|
-
|
|
125
|
-
elif isinstance(e, (Eager, Expose)):
|
|
126
|
-
return ()
|
|
127
|
-
|
|
128
|
-
else:
|
|
129
|
-
raise TypeError(e)
|
|
130
|
-
|
|
131
131
|
def _build_binding_impl_map(self, em: ta.Mapping[Key | None, ta.Sequence[Element]]) -> dict[Key, BindingImpl]:
|
|
132
132
|
pm: dict[Key, BindingImpl] = {}
|
|
133
|
-
mm: dict[Key, list[BindingImpl]] = {}
|
|
134
133
|
for k, es in em.items():
|
|
135
134
|
if k is None:
|
|
136
135
|
continue
|
|
137
136
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
137
|
+
es_by_ty = col.multi_map_by(type, es)
|
|
138
|
+
|
|
139
|
+
es_by_ty.pop(Eager, None)
|
|
140
|
+
es_by_ty.pop(Expose, None)
|
|
141
|
+
|
|
142
|
+
if (bs := es_by_ty.pop(Binding, None)):
|
|
143
|
+
if len(bs) > 1:
|
|
143
144
|
raise DuplicateKeyError(k)
|
|
144
|
-
[pm[k]] = bis
|
|
145
145
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
146
|
+
b: Binding = check.isinstance(check.single(bs), Binding)
|
|
147
|
+
p: ProviderImpl
|
|
148
|
+
|
|
149
|
+
if isinstance(b.provider, (SetProvider, MapProvider)):
|
|
150
|
+
p = make_multi_provider_impl(b.provider, es_by_ty)
|
|
151
|
+
|
|
152
|
+
else:
|
|
153
|
+
p = make_provider_impl(b.provider)
|
|
154
|
+
|
|
155
|
+
pm[k] = BindingImpl(b.key, p, b.scope, b)
|
|
156
|
+
|
|
157
|
+
if es_by_ty:
|
|
158
|
+
raise TypeError(set(es_by_ty))
|
|
150
159
|
|
|
151
160
|
return pm
|
|
152
161
|
|
omlish/inject/impl/injector.py
CHANGED
|
@@ -9,6 +9,7 @@ TODO:
|
|
|
9
9
|
- ** eagers in any scope, on scope init/open
|
|
10
10
|
- injection listeners
|
|
11
11
|
- unions - raise on ambiguous - usecase: sql.AsyncEngineLike
|
|
12
|
+
- multiple live request scopes on single injector - use private injectors?
|
|
12
13
|
"""
|
|
13
14
|
import contextlib
|
|
14
15
|
import typing as ta
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import typing as ta
|
|
2
|
+
|
|
3
|
+
from ... import dataclasses as dc
|
|
4
|
+
from ... import lang
|
|
5
|
+
from ..elements import Element
|
|
6
|
+
from ..injector import Injector
|
|
7
|
+
from ..multis import MapBinding
|
|
8
|
+
from ..multis import MapProvider
|
|
9
|
+
from ..multis import SetBinding
|
|
10
|
+
from ..multis import SetProvider
|
|
11
|
+
from ..providers import LinkProvider
|
|
12
|
+
from ..providers import Provider
|
|
13
|
+
from .providers import LinkProviderImpl
|
|
14
|
+
from .providers import ProviderImpl
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@dc.dataclass(frozen=True, eq=False)
|
|
18
|
+
class SetProviderImpl(ProviderImpl, lang.Final):
|
|
19
|
+
ps: ta.Sequence[ProviderImpl]
|
|
20
|
+
|
|
21
|
+
@property
|
|
22
|
+
def providers(self) -> ta.Iterable[Provider]:
|
|
23
|
+
for p in self.ps:
|
|
24
|
+
yield from p.providers
|
|
25
|
+
|
|
26
|
+
def provide(self, injector: Injector) -> ta.Any:
|
|
27
|
+
rv = set()
|
|
28
|
+
for ep in self.ps:
|
|
29
|
+
o = ep.provide(injector)
|
|
30
|
+
rv.add(o)
|
|
31
|
+
return rv
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
@dc.dataclass(frozen=True, eq=False)
|
|
35
|
+
class MapProviderImpl(ProviderImpl, lang.Final):
|
|
36
|
+
class Entry(ta.NamedTuple):
|
|
37
|
+
k: ta.Any
|
|
38
|
+
v: ProviderImpl
|
|
39
|
+
|
|
40
|
+
es: ta.Sequence[Entry]
|
|
41
|
+
|
|
42
|
+
@property
|
|
43
|
+
def providers(self) -> ta.Iterable[Provider]:
|
|
44
|
+
for e in self.es:
|
|
45
|
+
yield from e.v.providers
|
|
46
|
+
|
|
47
|
+
def provide(self, injector: Injector) -> ta.Any:
|
|
48
|
+
rv = {}
|
|
49
|
+
for e in self.es:
|
|
50
|
+
o = e.v.provide(injector)
|
|
51
|
+
rv[e.k] = o
|
|
52
|
+
return rv
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def make_multi_provider_impl(p: Provider, es_by_ty: ta.MutableMapping[type, list[Element]]) -> ProviderImpl:
|
|
56
|
+
if isinstance(p, SetProvider):
|
|
57
|
+
sbs: ta.Iterable[SetBinding] = es_by_ty.pop(SetBinding, ()) # type: ignore
|
|
58
|
+
return SetProviderImpl([
|
|
59
|
+
LinkProviderImpl(LinkProvider(sb.dst))
|
|
60
|
+
for sb in sbs
|
|
61
|
+
])
|
|
62
|
+
|
|
63
|
+
elif isinstance(p, MapProvider):
|
|
64
|
+
mbs: ta.Iterable[MapBinding] = es_by_ty.pop(MapBinding, ()) # type: ignore
|
|
65
|
+
return MapProviderImpl([
|
|
66
|
+
MapProviderImpl.Entry(
|
|
67
|
+
mb.map_key,
|
|
68
|
+
LinkProviderImpl(LinkProvider(mb.dst)),
|
|
69
|
+
)
|
|
70
|
+
for mb in mbs
|
|
71
|
+
])
|
|
72
|
+
|
|
73
|
+
else:
|
|
74
|
+
raise TypeError(p)
|
omlish/inject/impl/providers.py
CHANGED
|
@@ -5,10 +5,9 @@ TODO:
|
|
|
5
5
|
import abc
|
|
6
6
|
import typing as ta
|
|
7
7
|
|
|
8
|
-
from .. import Cls
|
|
9
|
-
from ... import check
|
|
10
8
|
from ... import dataclasses as dc
|
|
11
9
|
from ... import lang
|
|
10
|
+
from ... import reflect as rfl
|
|
12
11
|
from ..injector import Injector
|
|
13
12
|
from ..inspect import KwargsTarget
|
|
14
13
|
from ..providers import ConstProvider
|
|
@@ -19,6 +18,9 @@ from ..providers import Provider
|
|
|
19
18
|
from .inspect import build_kwargs_target
|
|
20
19
|
|
|
21
20
|
|
|
21
|
+
##
|
|
22
|
+
|
|
23
|
+
|
|
22
24
|
class ProviderImpl(lang.Abstract):
|
|
23
25
|
@property
|
|
24
26
|
@abc.abstractmethod
|
|
@@ -30,14 +32,20 @@ class ProviderImpl(lang.Abstract):
|
|
|
30
32
|
raise NotImplementedError
|
|
31
33
|
|
|
32
34
|
|
|
35
|
+
##
|
|
36
|
+
|
|
37
|
+
|
|
33
38
|
@dc.dataclass(frozen=True, eq=False)
|
|
34
39
|
class InternalProvider(Provider):
|
|
35
40
|
impl: ProviderImpl
|
|
36
41
|
|
|
37
|
-
def
|
|
42
|
+
def provided_ty(self) -> rfl.Type | None:
|
|
38
43
|
raise TypeError
|
|
39
44
|
|
|
40
45
|
|
|
46
|
+
##
|
|
47
|
+
|
|
48
|
+
|
|
41
49
|
@dc.dataclass(frozen=True, eq=False)
|
|
42
50
|
class CallableProviderImpl(ProviderImpl, lang.Final):
|
|
43
51
|
p: FnProvider | CtorProvider
|
|
@@ -51,6 +59,9 @@ class CallableProviderImpl(ProviderImpl, lang.Final):
|
|
|
51
59
|
return injector.inject(self.kt)
|
|
52
60
|
|
|
53
61
|
|
|
62
|
+
##
|
|
63
|
+
|
|
64
|
+
|
|
54
65
|
@dc.dataclass(frozen=True, eq=False)
|
|
55
66
|
class ConstProviderImpl(ProviderImpl, lang.Final):
|
|
56
67
|
p: ConstProvider
|
|
@@ -63,6 +74,9 @@ class ConstProviderImpl(ProviderImpl, lang.Final):
|
|
|
63
74
|
return self.p.v
|
|
64
75
|
|
|
65
76
|
|
|
77
|
+
##
|
|
78
|
+
|
|
79
|
+
|
|
66
80
|
@dc.dataclass(frozen=True, eq=False)
|
|
67
81
|
class LinkProviderImpl(ProviderImpl, lang.Final):
|
|
68
82
|
p: LinkProvider
|
|
@@ -75,46 +89,12 @@ class LinkProviderImpl(ProviderImpl, lang.Final):
|
|
|
75
89
|
return injector.provide(self.p.k)
|
|
76
90
|
|
|
77
91
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
def _unnest_multi_providers(ps: ta.Iterable[ProviderImpl]) -> ta.Sequence[ProviderImpl]:
|
|
82
|
-
lst = []
|
|
83
|
-
|
|
84
|
-
def rec(o):
|
|
85
|
-
if isinstance(o, MultiProviderImpl):
|
|
86
|
-
for c in o.ps:
|
|
87
|
-
rec(c)
|
|
88
|
-
else:
|
|
89
|
-
lst.append(check.isinstance(o, ProviderImpl))
|
|
90
|
-
|
|
91
|
-
for o in ps:
|
|
92
|
-
rec(o)
|
|
93
|
-
return tuple(lst)
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
@dc.dataclass(frozen=True, eq=False)
|
|
97
|
-
class MultiProviderImpl(ProviderImpl, lang.Final):
|
|
98
|
-
ps: ta.Sequence[ProviderImpl] = dc.xfield(coerce=_unnest_multi_providers)
|
|
99
|
-
|
|
100
|
-
@property
|
|
101
|
-
def providers(self) -> ta.Iterable[Provider]:
|
|
102
|
-
for p in self.ps:
|
|
103
|
-
yield from p.providers
|
|
104
|
-
|
|
105
|
-
def provide(self, injector: Injector) -> ta.Any:
|
|
106
|
-
rv = []
|
|
107
|
-
for ep in self.ps:
|
|
108
|
-
o = ep.provide(injector)
|
|
109
|
-
if isinstance(o, _ILLEGAL_MULTI_TYPES):
|
|
110
|
-
raise TypeError(o)
|
|
111
|
-
rv.extend(o)
|
|
112
|
-
return rv
|
|
92
|
+
##
|
|
113
93
|
|
|
114
94
|
|
|
115
95
|
PROVIDER_IMPLS_BY_PROVIDER: dict[type[Provider], ta.Callable[..., ProviderImpl]] = {
|
|
116
96
|
FnProvider: lambda p: CallableProviderImpl(p, build_kwargs_target(p.fn)),
|
|
117
|
-
CtorProvider: lambda p: CallableProviderImpl(p, build_kwargs_target(p.
|
|
97
|
+
CtorProvider: lambda p: CallableProviderImpl(p, build_kwargs_target(p.ty)),
|
|
118
98
|
ConstProvider: ConstProviderImpl,
|
|
119
99
|
LinkProvider: LinkProviderImpl,
|
|
120
100
|
InternalProvider: lambda p: p.impl,
|
omlish/inject/impl/scopes.py
CHANGED
omlish/inject/injector.py
CHANGED
omlish/inject/keys.py
CHANGED
|
@@ -3,6 +3,7 @@ import typing as ta
|
|
|
3
3
|
|
|
4
4
|
from .. import dataclasses as dc
|
|
5
5
|
from .. import lang
|
|
6
|
+
from .. import reflect as rfl
|
|
6
7
|
|
|
7
8
|
|
|
8
9
|
T = ta.TypeVar('T')
|
|
@@ -14,9 +15,8 @@ T = ta.TypeVar('T')
|
|
|
14
15
|
@dc.dataclass(frozen=True)
|
|
15
16
|
@dc.extra_params(cache_hash=True)
|
|
16
17
|
class Key(lang.Final, ta.Generic[T]):
|
|
17
|
-
|
|
18
|
+
ty: rfl.Type = dc.xfield(coerce=rfl.type_)
|
|
18
19
|
tag: ta.Any = dc.field(default=None, kw_only=True)
|
|
19
|
-
multi: bool = dc.field(default=False, kw_only=True)
|
|
20
20
|
|
|
21
21
|
|
|
22
22
|
##
|
|
@@ -27,17 +27,11 @@ def as_key(o: ta.Any) -> Key:
|
|
|
27
27
|
raise TypeError(o)
|
|
28
28
|
if isinstance(o, Key):
|
|
29
29
|
return o
|
|
30
|
-
|
|
31
|
-
return Key(o)
|
|
32
|
-
raise TypeError(o)
|
|
30
|
+
return Key(rfl.type_(o))
|
|
33
31
|
|
|
34
32
|
|
|
35
33
|
##
|
|
36
34
|
|
|
37
35
|
|
|
38
|
-
def multi(o: ta.Any) -> Key:
|
|
39
|
-
return dc.replace(as_key(o), multi=True)
|
|
40
|
-
|
|
41
|
-
|
|
42
36
|
def tag(o: ta.Any, t: ta.Any) -> Key:
|
|
43
37
|
return dc.replace(as_key(o), tag=t)
|
omlish/inject/multis.py
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"""
|
|
2
|
+
TODO:
|
|
3
|
+
- scopes
|
|
4
|
+
"""
|
|
5
|
+
import collections.abc
|
|
6
|
+
import typing as ta
|
|
7
|
+
|
|
8
|
+
from .. import dataclasses as dc
|
|
9
|
+
from .. import lang
|
|
10
|
+
from .. import reflect as rfl
|
|
11
|
+
from .bindings import Binding
|
|
12
|
+
from .elements import Element
|
|
13
|
+
from .keys import Key
|
|
14
|
+
from .keys import as_key
|
|
15
|
+
from .providers import Provider
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
##
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def _check_set_multi_key(mk: Key) -> bool:
|
|
22
|
+
return rfl.get_concrete_type(mk.ty) is collections.abc.Set
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
@dc.dataclass(frozen=True)
|
|
26
|
+
@dc.extra_params(cache_hash=True)
|
|
27
|
+
class SetBinding(Element, lang.Final):
|
|
28
|
+
multi_key: Key = dc.xfield(check=_check_set_multi_key)
|
|
29
|
+
dst: Key = dc.xfield()
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
@dc.dataclass(frozen=True, eq=False)
|
|
33
|
+
class SetProvider(Provider):
|
|
34
|
+
multi_key: Key = dc.xfield(check=_check_set_multi_key)
|
|
35
|
+
|
|
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
|
+
|
|
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(())
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
@dc.dataclass(frozen=True, eq=False)
|
|
61
|
+
class MapProvider(Provider):
|
|
62
|
+
multi_key: Key = dc.xfield(check=_check_map_multi_key)
|
|
63
|
+
|
|
64
|
+
def provided_ty(self) -> rfl.Type | None:
|
|
65
|
+
return self.multi_key.ty
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def bind_map_provider(multi_key: ta.Any) -> Element:
|
|
69
|
+
multi_key = as_key(multi_key)
|
|
70
|
+
return Binding(multi_key, MapProvider(multi_key))
|
omlish/inject/providers.py
CHANGED
|
@@ -4,12 +4,12 @@ import typing as ta
|
|
|
4
4
|
from .. import check
|
|
5
5
|
from .. import dataclasses as dc
|
|
6
6
|
from .. import lang
|
|
7
|
+
from .. import reflect as rfl
|
|
7
8
|
from .elements import Element
|
|
8
9
|
from .elements import Elements
|
|
9
10
|
from .impl.inspect import signature
|
|
10
11
|
from .keys import Key
|
|
11
12
|
from .keys import as_key
|
|
12
|
-
from .types import Cls
|
|
13
13
|
|
|
14
14
|
|
|
15
15
|
class _Missing(lang.NotInstantiable):
|
|
@@ -21,7 +21,7 @@ class _Missing(lang.NotInstantiable):
|
|
|
21
21
|
|
|
22
22
|
class Provider(lang.Abstract):
|
|
23
23
|
@abc.abstractmethod
|
|
24
|
-
def
|
|
24
|
+
def provided_ty(self) -> rfl.Type | None:
|
|
25
25
|
raise NotImplementedError
|
|
26
26
|
|
|
27
27
|
|
|
@@ -47,19 +47,19 @@ def as_provider(o: ta.Any) -> Provider:
|
|
|
47
47
|
@dc.dataclass(frozen=True, eq=False)
|
|
48
48
|
class FnProvider(Provider):
|
|
49
49
|
fn: ta.Any
|
|
50
|
-
|
|
50
|
+
ty: rfl.Type | None = None
|
|
51
51
|
|
|
52
|
-
def
|
|
53
|
-
return self.
|
|
52
|
+
def provided_ty(self) -> rfl.Type | None:
|
|
53
|
+
return self.ty
|
|
54
54
|
|
|
55
55
|
|
|
56
|
-
def fn(fn: ta.Any,
|
|
56
|
+
def fn(fn: ta.Any, ty: rfl.Type | None = _Missing) -> Provider:
|
|
57
57
|
check.not_isinstance(fn, type)
|
|
58
58
|
check.callable(fn)
|
|
59
|
-
if
|
|
59
|
+
if ty is _Missing:
|
|
60
60
|
sig = signature(fn)
|
|
61
|
-
|
|
62
|
-
return FnProvider(fn,
|
|
61
|
+
ty = check.isinstance(sig.return_annotation, type)
|
|
62
|
+
return FnProvider(fn, ty)
|
|
63
63
|
|
|
64
64
|
|
|
65
65
|
##
|
|
@@ -67,15 +67,15 @@ def fn(fn: ta.Any, cls: Cls | None = _Missing) -> Provider:
|
|
|
67
67
|
|
|
68
68
|
@dc.dataclass(frozen=True, eq=False)
|
|
69
69
|
class CtorProvider(Provider):
|
|
70
|
-
|
|
70
|
+
ty: type
|
|
71
71
|
|
|
72
|
-
def
|
|
73
|
-
return self.
|
|
72
|
+
def provided_ty(self) -> type:
|
|
73
|
+
return self.ty
|
|
74
74
|
|
|
75
75
|
|
|
76
|
-
def ctor(
|
|
77
|
-
check.isinstance(
|
|
78
|
-
return CtorProvider(
|
|
76
|
+
def ctor(ty: type) -> Provider:
|
|
77
|
+
check.isinstance(ty, type)
|
|
78
|
+
return CtorProvider(ty)
|
|
79
79
|
|
|
80
80
|
|
|
81
81
|
##
|
|
@@ -84,16 +84,16 @@ def ctor(cls: type) -> Provider:
|
|
|
84
84
|
@dc.dataclass(frozen=True, eq=False)
|
|
85
85
|
class ConstProvider(Provider):
|
|
86
86
|
v: ta.Any
|
|
87
|
-
|
|
87
|
+
ty: rfl.Type | None = None
|
|
88
88
|
|
|
89
|
-
def
|
|
90
|
-
return self.
|
|
89
|
+
def provided_ty(self) -> rfl.Type | None:
|
|
90
|
+
return self.ty
|
|
91
91
|
|
|
92
92
|
|
|
93
|
-
def const(v: ta.Any,
|
|
94
|
-
if
|
|
95
|
-
|
|
96
|
-
return ConstProvider(v,
|
|
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
97
|
|
|
98
98
|
|
|
99
99
|
##
|
|
@@ -103,7 +103,7 @@ def const(v: ta.Any, cls: Cls | None = _Missing) -> Provider:
|
|
|
103
103
|
class LinkProvider(Provider):
|
|
104
104
|
k: Key
|
|
105
105
|
|
|
106
|
-
def
|
|
106
|
+
def provided_ty(self) -> rfl.Type | None:
|
|
107
107
|
return None
|
|
108
108
|
|
|
109
109
|
|
omlish/inject/scopes.py
CHANGED
|
@@ -5,21 +5,25 @@ 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
10
|
from .bindings import as_binding
|
|
10
11
|
from .elements import Element
|
|
11
12
|
from .keys import Key
|
|
12
13
|
from .keys import as_key
|
|
13
14
|
from .providers import Provider
|
|
14
|
-
from .types import Cls
|
|
15
15
|
from .types import Scope
|
|
16
16
|
|
|
17
|
+
|
|
17
18
|
if ta.TYPE_CHECKING:
|
|
18
19
|
from . import injector as injector_
|
|
19
20
|
else:
|
|
20
21
|
injector_ = lang.proxy_import('.injector', __package__)
|
|
21
22
|
|
|
22
23
|
|
|
24
|
+
##
|
|
25
|
+
|
|
26
|
+
|
|
23
27
|
@dc.dataclass(frozen=True)
|
|
24
28
|
@dc.extra_params(cache_hash=True)
|
|
25
29
|
class ScopeBinding(Element, lang.Final):
|
|
@@ -65,8 +69,8 @@ class ScopeSeededProvider(Provider):
|
|
|
65
69
|
ss: SeededScope = dc.xfield(coerce=check.of_isinstance(SeededScope))
|
|
66
70
|
key: Key = dc.xfield(coerce=check.of_isinstance(Key))
|
|
67
71
|
|
|
68
|
-
def
|
|
69
|
-
return self.key.
|
|
72
|
+
def provided_ty(self) -> rfl.Type | None:
|
|
73
|
+
return self.key.ty
|
|
70
74
|
|
|
71
75
|
|
|
72
76
|
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/json.py
CHANGED
|
@@ -127,6 +127,7 @@ import typing as ta
|
|
|
127
127
|
|
|
128
128
|
from . import lang
|
|
129
129
|
|
|
130
|
+
|
|
130
131
|
if ta.TYPE_CHECKING:
|
|
131
132
|
import orjson as _orjson
|
|
132
133
|
import ujson as _ujson
|
|
@@ -165,7 +166,7 @@ dumps_pretty: ta.Callable[..., str] = functools.partial(dumps, **PRETTY_KWARGS)
|
|
|
165
166
|
COMPACT_SEPARATORS = (',', ':')
|
|
166
167
|
|
|
167
168
|
COMPACT_KWARGS: ta.Mapping[str, ta.Any] = dict(
|
|
168
|
-
indent=
|
|
169
|
+
indent=None,
|
|
169
170
|
separators=COMPACT_SEPARATORS,
|
|
170
171
|
)
|
|
171
172
|
|
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,
|
|
@@ -90,6 +92,7 @@ from .exceptions import ( # noqa
|
|
|
90
92
|
from .functions import ( # noqa
|
|
91
93
|
Args,
|
|
92
94
|
VoidError,
|
|
95
|
+
as_async,
|
|
93
96
|
constant,
|
|
94
97
|
finally_,
|
|
95
98
|
identity,
|
|
@@ -108,6 +111,7 @@ from .functions import ( # noqa
|
|
|
108
111
|
)
|
|
109
112
|
|
|
110
113
|
from .imports import ( # noqa
|
|
114
|
+
can_import,
|
|
111
115
|
import_all,
|
|
112
116
|
import_module,
|
|
113
117
|
import_module_attr,
|
omlish/lang/classes/restrict.py
CHANGED
omlish/lang/classes/virtual.py
CHANGED
|
@@ -3,8 +3,8 @@ import types
|
|
|
3
3
|
import typing as ta
|
|
4
4
|
|
|
5
5
|
from .abstract import make_abstract
|
|
6
|
-
from .restrict import NotInstantiable
|
|
7
6
|
from .restrict import Final
|
|
7
|
+
from .restrict import NotInstantiable
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
T = ta.TypeVar('T')
|
|
@@ -122,7 +122,7 @@ class Callable(NotInstantiable, Final, ta.Generic[T]):
|
|
|
122
122
|
|
|
123
123
|
@classmethod
|
|
124
124
|
def __subclasscheck__(cls, subclass: type) -> bool:
|
|
125
|
-
if not hasattr(subclass, '__call__'):
|
|
125
|
+
if not hasattr(subclass, '__call__'): # noqa
|
|
126
126
|
return False
|
|
127
127
|
call = subclass.__call__
|
|
128
128
|
if isinstance(call, types.MethodWrapperType) and call.__self__ is subclass:
|