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.

Files changed (143) hide show
  1. omlish/__about__.py +1 -1
  2. omlish/__init__.py +1 -1
  3. omlish/asyncs/__init__.py +10 -4
  4. omlish/asyncs/anyio.py +142 -12
  5. omlish/asyncs/asyncio.py +23 -0
  6. omlish/asyncs/asyncs.py +9 -6
  7. omlish/asyncs/bridge.py +316 -0
  8. omlish/asyncs/flavors.py +27 -1
  9. omlish/asyncs/trio_asyncio.py +28 -18
  10. omlish/c3.py +1 -1
  11. omlish/cached.py +1 -2
  12. omlish/collections/__init__.py +5 -1
  13. omlish/collections/cache/impl.py +1 -1
  14. omlish/collections/identity.py +7 -0
  15. omlish/collections/indexed.py +1 -1
  16. omlish/collections/utils.py +38 -6
  17. omlish/configs/__init__.py +5 -0
  18. omlish/configs/classes.py +53 -0
  19. omlish/configs/strings.py +94 -0
  20. omlish/dataclasses/__init__.py +9 -0
  21. omlish/dataclasses/impl/api.py +1 -1
  22. omlish/dataclasses/impl/as_.py +1 -1
  23. omlish/dataclasses/impl/copy.py +30 -0
  24. omlish/dataclasses/impl/exceptions.py +6 -0
  25. omlish/dataclasses/impl/fields.py +25 -25
  26. omlish/dataclasses/impl/init.py +5 -3
  27. omlish/dataclasses/impl/main.py +3 -0
  28. omlish/dataclasses/impl/metaclass.py +6 -1
  29. omlish/dataclasses/impl/order.py +1 -1
  30. omlish/dataclasses/impl/reflect.py +15 -2
  31. omlish/dataclasses/utils.py +44 -0
  32. omlish/defs.py +1 -1
  33. omlish/diag/__init__.py +4 -0
  34. omlish/diag/procfs.py +31 -3
  35. omlish/diag/procstats.py +32 -0
  36. omlish/{testing → diag}/pydevd.py +35 -0
  37. omlish/diag/replserver/console.py +3 -3
  38. omlish/diag/replserver/server.py +6 -5
  39. omlish/diag/threads.py +86 -0
  40. omlish/dispatch/_dispatch2.py +65 -0
  41. omlish/dispatch/_dispatch3.py +104 -0
  42. omlish/docker.py +20 -1
  43. omlish/fnpairs.py +37 -18
  44. omlish/graphs/dags.py +113 -0
  45. omlish/graphs/domination.py +268 -0
  46. omlish/graphs/trees.py +2 -2
  47. omlish/http/__init__.py +25 -0
  48. omlish/http/asgi.py +132 -0
  49. omlish/http/collections.py +15 -0
  50. omlish/http/consts.py +47 -5
  51. omlish/http/cookies.py +194 -0
  52. omlish/http/dates.py +70 -0
  53. omlish/http/encodings.py +6 -0
  54. omlish/http/json.py +273 -0
  55. omlish/http/sessions.py +204 -0
  56. omlish/inject/__init__.py +51 -17
  57. omlish/inject/binder.py +185 -5
  58. omlish/inject/bindings.py +3 -36
  59. omlish/inject/eagers.py +2 -8
  60. omlish/inject/elements.py +30 -9
  61. omlish/inject/exceptions.py +3 -3
  62. omlish/inject/impl/elements.py +65 -31
  63. omlish/inject/impl/injector.py +20 -2
  64. omlish/inject/impl/inspect.py +33 -5
  65. omlish/inject/impl/multis.py +74 -0
  66. omlish/inject/impl/origins.py +75 -0
  67. omlish/inject/impl/{private.py → privates.py} +2 -2
  68. omlish/inject/impl/providers.py +19 -39
  69. omlish/inject/{proxy.py → impl/proxy.py} +2 -2
  70. omlish/inject/impl/scopes.py +7 -2
  71. omlish/inject/injector.py +9 -4
  72. omlish/inject/inspect.py +18 -0
  73. omlish/inject/keys.py +11 -23
  74. omlish/inject/listeners.py +26 -0
  75. omlish/inject/managed.py +76 -10
  76. omlish/inject/multis.py +120 -0
  77. omlish/inject/origins.py +27 -0
  78. omlish/inject/overrides.py +5 -4
  79. omlish/inject/{private.py → privates.py} +6 -10
  80. omlish/inject/providers.py +12 -85
  81. omlish/inject/scopes.py +20 -9
  82. omlish/inject/types.py +2 -8
  83. omlish/iterators.py +13 -0
  84. omlish/lang/__init__.py +12 -2
  85. omlish/lang/cached.py +2 -2
  86. omlish/lang/classes/restrict.py +3 -2
  87. omlish/lang/classes/simple.py +18 -8
  88. omlish/lang/classes/virtual.py +2 -2
  89. omlish/lang/contextmanagers.py +75 -2
  90. omlish/lang/datetimes.py +6 -5
  91. omlish/lang/descriptors.py +131 -0
  92. omlish/lang/functions.py +18 -28
  93. omlish/lang/imports.py +11 -2
  94. omlish/lang/iterables.py +20 -1
  95. omlish/lang/typing.py +6 -0
  96. omlish/lifecycles/__init__.py +34 -0
  97. omlish/lifecycles/abstract.py +43 -0
  98. omlish/lifecycles/base.py +51 -0
  99. omlish/lifecycles/contextmanagers.py +74 -0
  100. omlish/lifecycles/controller.py +116 -0
  101. omlish/lifecycles/manager.py +161 -0
  102. omlish/lifecycles/states.py +43 -0
  103. omlish/lifecycles/transitions.py +64 -0
  104. omlish/logs/formatters.py +1 -1
  105. omlish/logs/utils.py +1 -1
  106. omlish/marshal/__init__.py +4 -0
  107. omlish/marshal/datetimes.py +1 -1
  108. omlish/marshal/naming.py +4 -0
  109. omlish/marshal/objects.py +1 -0
  110. omlish/marshal/polymorphism.py +4 -4
  111. omlish/reflect.py +139 -18
  112. omlish/secrets/__init__.py +7 -0
  113. omlish/secrets/marshal.py +41 -0
  114. omlish/secrets/passwords.py +120 -0
  115. omlish/secrets/secrets.py +47 -0
  116. omlish/serde/__init__.py +0 -0
  117. omlish/serde/dotenv.py +574 -0
  118. omlish/{json.py → serde/json.py} +4 -2
  119. omlish/serde/props.py +604 -0
  120. omlish/serde/yaml.py +223 -0
  121. omlish/sql/dbs.py +1 -1
  122. omlish/sql/duckdb.py +136 -0
  123. omlish/sql/sqlean.py +17 -0
  124. omlish/sync.py +70 -0
  125. omlish/term.py +7 -2
  126. omlish/testing/pytest/__init__.py +8 -2
  127. omlish/testing/pytest/helpers.py +0 -24
  128. omlish/testing/pytest/inject/harness.py +4 -4
  129. omlish/testing/pytest/marks.py +45 -0
  130. omlish/testing/pytest/plugins/__init__.py +3 -0
  131. omlish/testing/pytest/plugins/asyncs.py +136 -0
  132. omlish/testing/pytest/plugins/managermarks.py +60 -0
  133. omlish/testing/pytest/plugins/pydevd.py +1 -1
  134. omlish/testing/testing.py +10 -0
  135. omlish/text/delimit.py +4 -0
  136. omlish/text/glyphsplit.py +92 -0
  137. {omlish-0.0.0.dev4.dist-info → omlish-0.0.0.dev6.dist-info}/METADATA +1 -1
  138. omlish-0.0.0.dev6.dist-info/RECORD +240 -0
  139. {omlish-0.0.0.dev4.dist-info → omlish-0.0.0.dev6.dist-info}/WHEEL +1 -1
  140. omlish/configs/props.py +0 -64
  141. omlish-0.0.0.dev4.dist-info/RECORD +0 -195
  142. {omlish-0.0.0.dev4.dist-info → omlish-0.0.0.dev6.dist-info}/LICENSE +0 -0
  143. {omlish-0.0.0.dev4.dist-info → omlish-0.0.0.dev6.dist-info}/top_level.txt +0 -0
@@ -10,12 +10,16 @@ Multi's + Scopes:
10
10
 
11
11
  Element Types:
12
12
  - Binding
13
+ - ProvisionListenerBinding
14
+ - SetBinding
15
+ - MapBinding
13
16
  - Eager
14
17
  - Overrides
15
18
  - Expose
16
19
  - Private
17
20
  - ScopeBinding
18
21
  """
22
+ import copy
19
23
  import typing as ta
20
24
 
21
25
  from ... import check
@@ -25,22 +29,32 @@ from ..bindings import Binding
25
29
  from ..eagers import Eager
26
30
  from ..elements import Element
27
31
  from ..elements import Elements
28
- from ..exceptions import DuplicateKeyError
32
+ from ..exceptions import ConflictingKeyError
33
+ from ..exceptions import UnboundKeyError
29
34
  from ..keys import Key
35
+ from ..listeners import ProvisionListenerBinding
36
+ from ..multis import MapBinding
37
+ from ..multis import MapProvider
38
+ from ..multis import SetBinding
39
+ from ..multis import SetProvider
30
40
  from ..overrides import Overrides
31
- from ..private import Expose
32
- from ..private import Private
41
+ from ..privates import Expose
42
+ from ..privates import Private
33
43
  from ..scopes import ScopeBinding
34
44
  from ..types import Scope
35
45
  from .bindings import BindingImpl
36
- from .providers import MultiProviderImpl
46
+ from .multis import make_multi_provider_impl
47
+ from .origins import Origins
48
+ from .origins import set_origins
49
+ from .providers import ProviderImpl
37
50
  from .providers import make_provider_impl
38
51
  from .scopes import make_scope_impl
39
52
 
53
+
40
54
  if ta.TYPE_CHECKING:
41
- from . import private as private_
55
+ from . import privates as privates_
42
56
  else:
43
- private_ = lang.proxy_import('.private', __package__)
57
+ privates_ = lang.proxy_import('.privates', __package__)
44
58
 
45
59
 
46
60
  ElementT = ta.TypeVar('ElementT', bound=Element)
@@ -52,17 +66,17 @@ class ElementCollection(lang.Final):
52
66
 
53
67
  self._es = check.isinstance(es, Elements)
54
68
 
55
- self._private_infos: ta.MutableMapping[Private, private_.PrivateInfo] | None = None
69
+ self._private_infos: ta.MutableMapping[Private, privates_.PrivateInfo] | None = None
56
70
 
57
71
  ##
58
72
 
59
- def _get_private_info(self, p: Private) -> 'private_.PrivateInfo':
73
+ def _get_private_info(self, p: Private) -> 'privates_.PrivateInfo':
60
74
  if (pis := self._private_infos) is None:
61
75
  self._private_infos = pis = col.IdentityKeyDict()
62
76
  try:
63
77
  return pis[p]
64
78
  except KeyError:
65
- pis[p] = ec = private_.PrivateInfo(self, p)
79
+ pis[p] = ec = privates_.PrivateInfo(self, p)
66
80
  return ec
67
81
 
68
82
  ##
@@ -92,10 +106,16 @@ class ElementCollection(lang.Final):
92
106
  pi = self._get_private_info(e)
93
107
  self._build_raw_element_multimap(pi.owner_elements(), out)
94
108
 
109
+ elif isinstance(e, (SetBinding, MapBinding)):
110
+ add(e.multi_key, e)
111
+
112
+ elif isinstance(e, ProvisionListenerBinding):
113
+ add(None, e)
114
+
95
115
  elif isinstance(e, Overrides):
96
116
  ovr = self._build_raw_element_multimap(e.ovr)
97
117
  src = self._build_raw_element_multimap(e.src)
98
- for k, b in src.items():
118
+ for k, b in src.items(): # FIXME: merge None keys?
99
119
  try:
100
120
  bs = ovr[k]
101
121
  except KeyError:
@@ -117,36 +137,50 @@ class ElementCollection(lang.Final):
117
137
 
118
138
  ##
119
139
 
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 ()
140
+ def _get_single_binding(self, k: Key, bs: ta.Sequence[Binding]) -> Binding:
141
+ if not bs:
142
+ raise UnboundKeyError(k)
143
+
144
+ elif len(bs) > 1:
145
+ d: dict = {}
146
+ for b in bs:
147
+ d.setdefault(b, []).append(b)
148
+ if len(d) > 1:
149
+ raise ConflictingKeyError(k)
150
+ l = check.single(d.values())
151
+ b = copy.copy(l[0])
152
+ set_origins(b, Origins(tuple(o for c in l for o in c.origins)))
153
+ return b
127
154
 
128
155
  else:
129
- raise TypeError(e)
156
+ return check.isinstance(check.single(bs), Binding)
130
157
 
131
158
  def _build_binding_impl_map(self, em: ta.Mapping[Key | None, ta.Sequence[Element]]) -> dict[Key, BindingImpl]:
132
159
  pm: dict[Key, BindingImpl] = {}
133
- mm: dict[Key, list[BindingImpl]] = {}
134
160
  for k, es in em.items():
135
161
  if k is None:
136
162
  continue
137
163
 
138
- bis = [bi for e in es for bi in self._make_binding_impls(e)]
139
- if k.multi:
140
- mm.setdefault(k, []).extend(bis)
141
- else:
142
- if len(bis) > 1:
143
- raise DuplicateKeyError(k)
144
- [pm[k]] = bis
145
-
146
- if mm:
147
- for k, aps in mm.items():
148
- mp = MultiProviderImpl([ap.provider for ap in aps])
149
- pm[k] = BindingImpl(k, mp) # FIXME: SCOPING
164
+ es_by_ty = col.multi_map_by(type, es)
165
+
166
+ es_by_ty.pop(Eager, None)
167
+ es_by_ty.pop(Expose, None)
168
+ es_by_ty.pop(ProvisionListenerBinding, None)
169
+
170
+ if (bs := es_by_ty.pop(Binding, None)):
171
+ b = self._get_single_binding(k, bs) # type: ignore
172
+
173
+ p: ProviderImpl
174
+ if isinstance(b.provider, (SetProvider, MapProvider)):
175
+ p = make_multi_provider_impl(b.provider, es_by_ty)
176
+
177
+ else:
178
+ p = make_provider_impl(b.provider)
179
+
180
+ pm[k] = BindingImpl(b.key, p, b.scope, b)
181
+
182
+ if es_by_ty:
183
+ raise TypeError(set(es_by_ty))
150
184
 
151
185
  return pm
152
186
 
@@ -9,8 +9,11 @@ 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
15
+ import functools
16
+ import itertools
14
17
  import typing as ta
15
18
  import weakref
16
19
 
@@ -23,6 +26,8 @@ from ..injector import Injector
23
26
  from ..inspect import KwargsTarget
24
27
  from ..keys import Key
25
28
  from ..keys import as_key
29
+ from ..listeners import ProvisionListener
30
+ from ..listeners import ProvisionListenerBinding
26
31
  from ..scopes import ScopeBinding
27
32
  from ..scopes import Singleton
28
33
  from ..scopes import Thread
@@ -54,6 +59,13 @@ class InjectorImpl(Injector, lang.Final):
54
59
 
55
60
  self._bim = ec.binding_impl_map()
56
61
  self._ekbs = ec.eager_keys_by_scope()
62
+ self._pls: tuple[ProvisionListener, ...] = tuple(
63
+ b.listener
64
+ for b in itertools.chain(
65
+ ec.elements_of_type(ProvisionListenerBinding),
66
+ (p._pls if p is not None else ()), # noqa
67
+ )
68
+ )
57
69
 
58
70
  self._cs: weakref.WeakSet[InjectorImpl] | None = None
59
71
  self._root: InjectorImpl = p._root if p is not None else self # noqa
@@ -69,6 +81,7 @@ class InjectorImpl(Injector, lang.Final):
69
81
  }
70
82
 
71
83
  self._instantiate_eagers(Unscoped())
84
+ self._instantiate_eagers(Singleton())
72
85
 
73
86
  _root: 'InjectorImpl'
74
87
 
@@ -108,7 +121,7 @@ class InjectorImpl(Injector, lang.Final):
108
121
  check.not_in(key, self._provisions)
109
122
  self._provisions[key] = v
110
123
 
111
- def __enter__(self: ta.Self) -> ta.Self:
124
+ def __enter__(self) -> ta.Self:
112
125
  return self
113
126
 
114
127
  def __exit__(self, *exc) -> None:
@@ -141,7 +154,12 @@ class InjectorImpl(Injector, lang.Final):
141
154
  bi = self._bim.get(key)
142
155
  if bi is not None:
143
156
  sc = self._scopes[bi.scope]
144
- v = sc.provide(bi, self)
157
+
158
+ fn = lambda: sc.provide(bi, self) # noqa
159
+ for pl in self._pls:
160
+ fn = functools.partial(pl, self, key, bi.binding, fn)
161
+ v = fn()
162
+
145
163
  cr.handle_provision(key, v)
146
164
  return lang.just(v)
147
165
 
@@ -5,24 +5,29 @@ TODO:
5
5
  - tag decorator - @inj.tag(x='foo')
6
6
  - *unpack optional here*
7
7
  """
8
+ import dataclasses as dc
8
9
  import inspect
9
10
  import types
10
11
  import typing as ta
11
12
  import weakref
12
13
 
13
14
  from ... import reflect as rfl
14
- from ..exceptions import DuplicateKeyError
15
+ from ..exceptions import ConflictingKeyError
15
16
  from ..inspect import Kwarg
16
17
  from ..inspect import KwargsTarget
17
18
  from ..keys import Key
18
19
  from ..keys import as_key
19
- from ..keys import tag
20
+ from ..types import Tag
20
21
 
21
22
 
23
+ T = ta.TypeVar('T')
22
24
  P = ta.ParamSpec('P')
23
25
  R = ta.TypeVar('R')
24
26
 
25
27
 
28
+ ##
29
+
30
+
26
31
  _signature_cache: ta.MutableMapping[ta.Any, inspect.Signature] = weakref.WeakKeyDictionary()
27
32
 
28
33
 
@@ -38,9 +43,20 @@ def signature(obj: ta.Any) -> inspect.Signature:
38
43
  return sig
39
44
 
40
45
 
46
+ ##
47
+
48
+
41
49
  _tags: ta.MutableMapping[ta.Any, dict[str, ta.Any]] = weakref.WeakKeyDictionary()
42
50
 
43
51
 
52
+ def tag(obj: T, **kwargs: ta.Any) -> T:
53
+ for v in kwargs.values():
54
+ if isinstance(v, Tag):
55
+ raise TypeError(v)
56
+ _tags.setdefault(obj, {}).update(**kwargs)
57
+ return obj
58
+
59
+
44
60
  def tags(**kwargs: ta.Any) -> ta.Callable[[ta.Callable[P, R]], ta.Callable[P, R]]:
45
61
  def inner(obj):
46
62
  _tags[obj] = kwargs
@@ -48,6 +64,9 @@ def tags(**kwargs: ta.Any) -> ta.Callable[[ta.Callable[P, R]], ta.Callable[P, R]
48
64
  return inner
49
65
 
50
66
 
67
+ ##
68
+
69
+
51
70
  def build_kwargs_target(
52
71
  obj: ta.Any,
53
72
  *,
@@ -78,12 +97,21 @@ def build_kwargs_target(
78
97
  ):
79
98
  [ann] = [a for a in rf.args if a is not types.NoneType]
80
99
 
81
- k = as_key(ann)
100
+ rty = rfl.type_(ann)
101
+
102
+ tag = None
103
+ if isinstance(rty, rfl.Annotated):
104
+ for e in rty.md:
105
+ if isinstance(e, Tag):
106
+ tag = e.tag
107
+ break
108
+
109
+ k: Key = Key(rfl.strip_annotations(rty), tag=tag)
82
110
  if tags is not None and (pt := tags.get(p.name)) is not None:
83
- k = tag(k, pt)
111
+ k = dc.replace(k, tag=pt)
84
112
 
85
113
  if k in seen:
86
- raise DuplicateKeyError(k)
114
+ raise ConflictingKeyError(k)
87
115
  seen.add(k)
88
116
 
89
117
  kws.append(Kwarg(
@@ -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)
@@ -0,0 +1,75 @@
1
+ import sys
2
+ import types
3
+ import typing as ta
4
+
5
+ from ... import dataclasses as dc
6
+ from ... import lang
7
+ from ..origins import HasOrigins
8
+ from ..origins import Origin
9
+ from ..origins import Origins
10
+
11
+
12
+ HasOriginsT = ta.TypeVar('HasOriginsT', bound=HasOrigins)
13
+
14
+
15
+ ##
16
+
17
+
18
+ ORIGIN_NUM_FRAMES = 8
19
+ ORIGIN_BASE_OFS = 2
20
+
21
+ ORIGIN_IGNORED_PACKAGES = frozenset([
22
+ __package__,
23
+ __package__.rpartition('.')[0],
24
+
25
+ lang.__name__,
26
+ lang.functions.__name__,
27
+
28
+ dc.__name__,
29
+ dc.impl.__name__, # noqa
30
+ ])
31
+
32
+
33
+ def is_origin_frame(f: types.FrameType) -> bool:
34
+ gl = f.f_globals
35
+ try:
36
+ pkg = gl['__package__']
37
+ except KeyError:
38
+ pass
39
+ else:
40
+ if pkg in ORIGIN_IGNORED_PACKAGES:
41
+ return False
42
+ return True
43
+
44
+
45
+ def build_origin(ofs: int = 0) -> Origin:
46
+ lst = [] # type: ignore
47
+ cur = sys._getframe(ORIGIN_BASE_OFS + ofs) # noqa
48
+ while len(lst) < ORIGIN_NUM_FRAMES and cur is not None:
49
+ if is_origin_frame(cur):
50
+ lst.append(cur)
51
+ cur = cur.f_back # type: ignore
52
+ return Origin(tuple(str(f) for f in lst))
53
+
54
+
55
+ ##
56
+
57
+
58
+ ORIGINS_ATTR = '__inject_origins__'
59
+
60
+
61
+ def set_origins(obj: HasOriginsT, origins: Origins) -> HasOriginsT:
62
+ obj.__dict__[ORIGINS_ATTR] = origins
63
+ return obj
64
+
65
+
66
+ class HasOriginsImpl(HasOrigins):
67
+ @property
68
+ def origins(self) -> Origins:
69
+ return self.__dict__[ORIGINS_ATTR]
70
+
71
+ def __post_init__(self) -> None:
72
+ dc.maybe_post_init(super())
73
+ if ORIGINS_ATTR in self.__dict__:
74
+ raise AttributeError('Origin already set')
75
+ set_origins(self, Origins((build_origin(),)))
@@ -14,8 +14,8 @@ from ..eagers import Eager
14
14
  from ..elements import Element
15
15
  from ..injector import Injector
16
16
  from ..keys import Key
17
- from ..private import Expose
18
- from ..private import Private
17
+ from ..privates import Expose
18
+ from ..privates import Private
19
19
  from ..providers import Provider
20
20
  from ..scopes import Singleton
21
21
  from .elements import ElementCollection
@@ -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 provided_cls(self) -> Cls | None:
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
- _ILLEGAL_MULTI_TYPES = (str, bytes, bytearray)
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.cls)),
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,
@@ -1,7 +1,7 @@
1
1
  import typing as ta
2
2
 
3
- from .. import lang
4
- from .. import check
3
+ from ... import check
4
+ from ... import lang
5
5
 
6
6
 
7
7
  @lang.cached_function
@@ -1,3 +1,7 @@
1
+ """
2
+ TODO:
3
+ - ContextVar ('context')
4
+ """
1
5
  import abc
2
6
  import contextlib
3
7
  import threading
@@ -13,8 +17,8 @@ from ..exceptions import ScopeAlreadyOpenError
13
17
  from ..exceptions import ScopeNotOpenError
14
18
  from ..injector import Injector
15
19
  from ..keys import Key
20
+ from ..providers import FnProvider
16
21
  from ..providers import Provider
17
- from ..providers import fn
18
22
  from ..scopes import ScopeSeededProvider
19
23
  from ..scopes import SeededScope
20
24
  from ..scopes import Singleton
@@ -25,6 +29,7 @@ from .bindings import BindingImpl
25
29
  from .providers import PROVIDER_IMPLS_BY_PROVIDER
26
30
  from .providers import ProviderImpl
27
31
 
32
+
28
33
  if ta.TYPE_CHECKING:
29
34
  from . import injector as injector_
30
35
  else:
@@ -161,7 +166,7 @@ class SeededScopeImpl(ScopeImpl):
161
166
  return as_elements(
162
167
  Binding(
163
168
  Key(SeededScope.Manager, tag=self._ss),
164
- fn(lang.typed_partial(SeededScopeImpl.Manager, ss=self._ss)),
169
+ FnProvider(lang.typed_partial(SeededScopeImpl.Manager, ss=self._ss)),
165
170
  scope=Singleton(),
166
171
  ),
167
172
  )
omlish/inject/injector.py CHANGED
@@ -2,11 +2,16 @@ import abc
2
2
  import typing as ta
3
3
 
4
4
  from .. import lang
5
- from .elements import Elements
5
+ from .elements import Elemental
6
+ from .elements import as_elements
6
7
  from .inspect import KwargsTarget
7
8
  from .keys import Key
8
9
 
9
- _impl = lang.proxy_import('.impl.injector', __package__)
10
+
11
+ if ta.TYPE_CHECKING:
12
+ from .impl import injector as _injector
13
+ else:
14
+ _injector = lang.proxy_import('.impl.injector', __package__)
10
15
 
11
16
 
12
17
  T = ta.TypeVar('T')
@@ -36,5 +41,5 @@ class Injector(lang.Abstract):
36
41
  return self.provide(target)
37
42
 
38
43
 
39
- def create_injector(es: Elements) -> Injector:
40
- return _impl.create_injector(es)
44
+ def create_injector(*args: Elemental) -> Injector:
45
+ return _injector.create_injector(as_elements(*args))
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)