omlish 0.0.0.dev1__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 (187) hide show
  1. omlish/__about__.py +7 -0
  2. omlish/__init__.py +0 -0
  3. omlish/argparse.py +223 -0
  4. omlish/asyncs/__init__.py +17 -0
  5. omlish/asyncs/anyio.py +23 -0
  6. omlish/asyncs/asyncio.py +19 -0
  7. omlish/asyncs/asyncs.py +76 -0
  8. omlish/asyncs/futures.py +179 -0
  9. omlish/asyncs/trio.py +11 -0
  10. omlish/c3.py +173 -0
  11. omlish/cached.py +9 -0
  12. omlish/check.py +231 -0
  13. omlish/collections/__init__.py +63 -0
  14. omlish/collections/_abc.py +156 -0
  15. omlish/collections/_io_abc.py +78 -0
  16. omlish/collections/cache/__init__.py +11 -0
  17. omlish/collections/cache/descriptor.py +188 -0
  18. omlish/collections/cache/impl.py +485 -0
  19. omlish/collections/cache/types.py +37 -0
  20. omlish/collections/coerce.py +337 -0
  21. omlish/collections/frozen.py +148 -0
  22. omlish/collections/identity.py +106 -0
  23. omlish/collections/indexed.py +75 -0
  24. omlish/collections/mappings.py +127 -0
  25. omlish/collections/ordered.py +81 -0
  26. omlish/collections/persistent.py +36 -0
  27. omlish/collections/skiplist.py +193 -0
  28. omlish/collections/sorted.py +126 -0
  29. omlish/collections/treap.py +228 -0
  30. omlish/collections/treapmap.py +144 -0
  31. omlish/collections/unmodifiable.py +174 -0
  32. omlish/collections/utils.py +110 -0
  33. omlish/configs/__init__.py +0 -0
  34. omlish/configs/flattening.py +147 -0
  35. omlish/configs/props.py +64 -0
  36. omlish/dataclasses/__init__.py +83 -0
  37. omlish/dataclasses/impl/__init__.py +6 -0
  38. omlish/dataclasses/impl/api.py +260 -0
  39. omlish/dataclasses/impl/as_.py +76 -0
  40. omlish/dataclasses/impl/exceptions.py +2 -0
  41. omlish/dataclasses/impl/fields.py +148 -0
  42. omlish/dataclasses/impl/frozen.py +55 -0
  43. omlish/dataclasses/impl/hashing.py +85 -0
  44. omlish/dataclasses/impl/init.py +173 -0
  45. omlish/dataclasses/impl/internals.py +118 -0
  46. omlish/dataclasses/impl/main.py +150 -0
  47. omlish/dataclasses/impl/metaclass.py +126 -0
  48. omlish/dataclasses/impl/metadata.py +74 -0
  49. omlish/dataclasses/impl/order.py +47 -0
  50. omlish/dataclasses/impl/params.py +150 -0
  51. omlish/dataclasses/impl/processing.py +16 -0
  52. omlish/dataclasses/impl/reflect.py +173 -0
  53. omlish/dataclasses/impl/replace.py +40 -0
  54. omlish/dataclasses/impl/repr.py +34 -0
  55. omlish/dataclasses/impl/simple.py +92 -0
  56. omlish/dataclasses/impl/slots.py +80 -0
  57. omlish/dataclasses/impl/utils.py +167 -0
  58. omlish/defs.py +193 -0
  59. omlish/dispatch/__init__.py +3 -0
  60. omlish/dispatch/dispatch.py +137 -0
  61. omlish/dispatch/functions.py +52 -0
  62. omlish/dispatch/methods.py +162 -0
  63. omlish/docker.py +149 -0
  64. omlish/dynamic.py +220 -0
  65. omlish/graphs/__init__.py +0 -0
  66. omlish/graphs/dot/__init__.py +19 -0
  67. omlish/graphs/dot/items.py +162 -0
  68. omlish/graphs/dot/rendering.py +147 -0
  69. omlish/graphs/dot/utils.py +30 -0
  70. omlish/graphs/trees.py +249 -0
  71. omlish/http/__init__.py +0 -0
  72. omlish/http/consts.py +20 -0
  73. omlish/http/wsgi.py +34 -0
  74. omlish/inject/__init__.py +85 -0
  75. omlish/inject/binder.py +12 -0
  76. omlish/inject/bindings.py +49 -0
  77. omlish/inject/eagers.py +21 -0
  78. omlish/inject/elements.py +43 -0
  79. omlish/inject/exceptions.py +49 -0
  80. omlish/inject/impl/__init__.py +0 -0
  81. omlish/inject/impl/bindings.py +19 -0
  82. omlish/inject/impl/elements.py +154 -0
  83. omlish/inject/impl/injector.py +182 -0
  84. omlish/inject/impl/inspect.py +98 -0
  85. omlish/inject/impl/private.py +109 -0
  86. omlish/inject/impl/providers.py +132 -0
  87. omlish/inject/impl/scopes.py +198 -0
  88. omlish/inject/injector.py +40 -0
  89. omlish/inject/inspect.py +14 -0
  90. omlish/inject/keys.py +43 -0
  91. omlish/inject/managed.py +24 -0
  92. omlish/inject/overrides.py +18 -0
  93. omlish/inject/private.py +29 -0
  94. omlish/inject/providers.py +111 -0
  95. omlish/inject/proxy.py +48 -0
  96. omlish/inject/scopes.py +84 -0
  97. omlish/inject/types.py +21 -0
  98. omlish/iterators.py +184 -0
  99. omlish/json.py +194 -0
  100. omlish/lang/__init__.py +112 -0
  101. omlish/lang/cached.py +267 -0
  102. omlish/lang/classes/__init__.py +24 -0
  103. omlish/lang/classes/abstract.py +74 -0
  104. omlish/lang/classes/restrict.py +137 -0
  105. omlish/lang/classes/simple.py +120 -0
  106. omlish/lang/classes/test/__init__.py +0 -0
  107. omlish/lang/classes/test/test_abstract.py +89 -0
  108. omlish/lang/classes/test/test_restrict.py +71 -0
  109. omlish/lang/classes/test/test_simple.py +58 -0
  110. omlish/lang/classes/test/test_virtual.py +72 -0
  111. omlish/lang/classes/virtual.py +130 -0
  112. omlish/lang/clsdct.py +67 -0
  113. omlish/lang/cmp.py +63 -0
  114. omlish/lang/contextmanagers.py +249 -0
  115. omlish/lang/datetimes.py +67 -0
  116. omlish/lang/descriptors.py +52 -0
  117. omlish/lang/functions.py +126 -0
  118. omlish/lang/imports.py +153 -0
  119. omlish/lang/iterables.py +54 -0
  120. omlish/lang/maybes.py +136 -0
  121. omlish/lang/objects.py +103 -0
  122. omlish/lang/resolving.py +50 -0
  123. omlish/lang/strings.py +128 -0
  124. omlish/lang/typing.py +92 -0
  125. omlish/libc.py +532 -0
  126. omlish/logs/__init__.py +9 -0
  127. omlish/logs/_abc.py +247 -0
  128. omlish/logs/configs.py +62 -0
  129. omlish/logs/filters.py +9 -0
  130. omlish/logs/formatters.py +67 -0
  131. omlish/logs/utils.py +20 -0
  132. omlish/marshal/__init__.py +52 -0
  133. omlish/marshal/any.py +25 -0
  134. omlish/marshal/base.py +201 -0
  135. omlish/marshal/base64.py +25 -0
  136. omlish/marshal/dataclasses.py +115 -0
  137. omlish/marshal/datetimes.py +90 -0
  138. omlish/marshal/enums.py +43 -0
  139. omlish/marshal/exceptions.py +7 -0
  140. omlish/marshal/factories.py +129 -0
  141. omlish/marshal/global_.py +33 -0
  142. omlish/marshal/iterables.py +57 -0
  143. omlish/marshal/mappings.py +66 -0
  144. omlish/marshal/naming.py +17 -0
  145. omlish/marshal/objects.py +106 -0
  146. omlish/marshal/optionals.py +49 -0
  147. omlish/marshal/polymorphism.py +147 -0
  148. omlish/marshal/primitives.py +43 -0
  149. omlish/marshal/registries.py +57 -0
  150. omlish/marshal/standard.py +80 -0
  151. omlish/marshal/utils.py +23 -0
  152. omlish/marshal/uuids.py +29 -0
  153. omlish/marshal/values.py +30 -0
  154. omlish/math.py +184 -0
  155. omlish/os.py +32 -0
  156. omlish/reflect.py +359 -0
  157. omlish/replserver/__init__.py +5 -0
  158. omlish/replserver/__main__.py +4 -0
  159. omlish/replserver/console.py +247 -0
  160. omlish/replserver/server.py +146 -0
  161. omlish/runmodule.py +28 -0
  162. omlish/stats.py +342 -0
  163. omlish/term.py +222 -0
  164. omlish/testing/__init__.py +7 -0
  165. omlish/testing/pydevd.py +225 -0
  166. omlish/testing/pytest/__init__.py +8 -0
  167. omlish/testing/pytest/helpers.py +35 -0
  168. omlish/testing/pytest/inject/__init__.py +1 -0
  169. omlish/testing/pytest/inject/harness.py +159 -0
  170. omlish/testing/pytest/plugins/__init__.py +20 -0
  171. omlish/testing/pytest/plugins/_registry.py +6 -0
  172. omlish/testing/pytest/plugins/logging.py +13 -0
  173. omlish/testing/pytest/plugins/pycharm.py +54 -0
  174. omlish/testing/pytest/plugins/repeat.py +19 -0
  175. omlish/testing/pytest/plugins/skips.py +32 -0
  176. omlish/testing/pytest/plugins/spacing.py +19 -0
  177. omlish/testing/pytest/plugins/switches.py +70 -0
  178. omlish/testing/testing.py +102 -0
  179. omlish/text/__init__.py +0 -0
  180. omlish/text/delimit.py +171 -0
  181. omlish/text/indent.py +50 -0
  182. omlish/text/parts.py +265 -0
  183. omlish-0.0.0.dev1.dist-info/LICENSE +21 -0
  184. omlish-0.0.0.dev1.dist-info/METADATA +17 -0
  185. omlish-0.0.0.dev1.dist-info/RECORD +187 -0
  186. omlish-0.0.0.dev1.dist-info/WHEEL +5 -0
  187. omlish-0.0.0.dev1.dist-info/top_level.txt +1 -0
omlish/graphs/trees.py ADDED
@@ -0,0 +1,249 @@
1
+ """
2
+ TODO:
3
+ - @property dfs, bfs
4
+ """
5
+ import functools
6
+ import typing as ta
7
+ import weakref
8
+
9
+ from .. import cached
10
+ from .. import check
11
+ from .. import collections as col
12
+ from .. import lang
13
+
14
+
15
+ T = ta.TypeVar('T')
16
+ NodeT = ta.TypeVar('NodeT')
17
+ NodeWalker = ta.Callable[[NodeT], ta.Iterable[NodeT]]
18
+ NodeGenerator = ta.Generator[NodeT, None, None]
19
+
20
+
21
+ class NodeException(ta.Generic[NodeT], Exception):
22
+ def __init__(self, node: NodeT, msg: str, *args, **kwargs) -> None:
23
+ super().__init__(msg, *args, **kwargs) # noqa
24
+ self._node = node
25
+
26
+ @property
27
+ def node(self) -> NodeT:
28
+ return self._node
29
+
30
+
31
+ class DuplicateNodeException(NodeException[NodeT]):
32
+ def __init__(self, node: NodeT, *args, **kwargs) -> None:
33
+ super().__init__(node, f'Duplicate node: {node!r}', *args, **kwargs)
34
+
35
+
36
+ class UnknownNodeException(NodeException[NodeT]):
37
+ def __init__(self, node: NodeT, *args, **kwargs) -> None:
38
+ super().__init__(node, f'Unknown node: {node!r}', *args, **kwargs)
39
+
40
+
41
+ class BasicTreeAnalysis(ta.Generic[NodeT]):
42
+
43
+ def __init__(
44
+ self,
45
+ root: NodeT,
46
+ walker: NodeWalker[NodeT],
47
+ *,
48
+ identity: bool = False,
49
+ ) -> None:
50
+ super().__init__()
51
+
52
+ self._root = root
53
+ self._walker = walker
54
+ self._identity = identity
55
+
56
+ self._set_fac: ta.Callable[..., ta.MutableSet[NodeT]] = col.IdentitySet if identity else set
57
+ self._dict_fac: ta.Callable[..., ta.MutableMapping[NodeT, ta.Any]] = col.IdentityKeyDict if identity else dict
58
+ self._idx_seq_fac: ta.Callable[..., col.IndexedSeq[NodeT]] = functools.partial(col.IndexedSeq, identity=identity) # noqa
59
+
60
+ def walk(cur: NodeT, parent: ta.Optional[NodeT]) -> None:
61
+ check.not_none(cur)
62
+ if cur in node_set:
63
+ raise DuplicateNodeException(cur)
64
+
65
+ nodes.append(cur)
66
+ node_set.add(cur)
67
+ if parent is None:
68
+ check.state(cur is root)
69
+ elif parent not in node_set:
70
+ raise UnknownNodeException(parent)
71
+
72
+ parents_by_node[cur] = parent
73
+
74
+ children_by_node[cur] = children = list(walker(cur))
75
+ child_sets_by_node[cur] = self._set_fac(children)
76
+ for child in children:
77
+ walk(child, cur)
78
+
79
+ nodes: list[NodeT] = []
80
+ node_set: ta.MutableSet[NodeT] = self._set_fac() # type: ignore
81
+ children_by_node: ta.MutableMapping[ta.Optional[NodeT], ta.Sequence[NodeT]] = self._dict_fac() # type: ignore
82
+ child_sets_by_node: ta.MutableMapping[ta.Optional[NodeT], ta.AbstractSet[NodeT]] = self._dict_fac() # type: ignore # noqa
83
+ parents_by_node: ta.MutableMapping[NodeT, ta.Optional[NodeT]] = self._dict_fac() # type: ignore
84
+
85
+ children_by_node[None] = [root]
86
+ child_sets_by_node[None] = self._set_fac([root]) # type: ignore
87
+
88
+ walk(root, None)
89
+
90
+ self._nodes = self._idx_seq_fac(nodes) # type: ignore
91
+ self._node_set: ta.AbstractSet[NodeT] = node_set
92
+ self._children_by_node: ta.Mapping[ta.Optional[NodeT], col.IndexedSeq[NodeT]] = self._dict_fac( # type: ignore
93
+ [(n, self._idx_seq_fac(cs)) for n, cs in children_by_node.items()])
94
+ self._child_sets_by_node: ta.Mapping[ta.Optional[NodeT], ta.AbstractSet[NodeT]] = child_sets_by_node
95
+ self._parents_by_node: ta.Mapping[NodeT, ta.Optional[NodeT]] = parents_by_node
96
+
97
+ @property
98
+ def root(self) -> NodeT:
99
+ return self._root
100
+
101
+ @property
102
+ def nodes(self) -> col.IndexedSeq[NodeT]:
103
+ return self._nodes
104
+
105
+ @property
106
+ def walker(self) -> NodeWalker[NodeT]:
107
+ return self._walker
108
+
109
+ @property
110
+ def identity(self) -> bool:
111
+ return self._identity
112
+
113
+ @property
114
+ def node_set(self) -> ta.AbstractSet[NodeT]:
115
+ return self._node_set
116
+
117
+ @property
118
+ def children_by_node(self) -> ta.Mapping[ta.Optional[NodeT], col.IndexedSeq[NodeT]]:
119
+ return self._children_by_node
120
+
121
+ @property
122
+ def child_sets_by_node(self) -> ta.Mapping[ta.Optional[NodeT], ta.AbstractSet[NodeT]]:
123
+ return self._child_sets_by_node
124
+
125
+ @property
126
+ def parents_by_node(self) -> ta.Mapping[NodeT, ta.Optional[NodeT]]:
127
+ return self._parents_by_node
128
+
129
+ @classmethod
130
+ def from_parents(
131
+ cls,
132
+ src: ta.Union[
133
+ ta.Mapping[NodeT, ta.Optional[NodeT]],
134
+ ta.Iterable[tuple[NodeT, ta.Optional[NodeT]]],
135
+ ],
136
+ *,
137
+ identity: bool = False,
138
+ **kwargs
139
+ ) -> 'BasicTreeAnalysis[NodeT]':
140
+ pairs: ta.Sequence[tuple[NodeT, NodeT]]
141
+ if isinstance(src, ta.Mapping):
142
+ pairs = list(src.items()) # type: ignore
143
+ elif isinstance(src, ta.Iterable):
144
+ pairs = list(src) # type: ignore
145
+ else:
146
+ raise TypeError(src)
147
+
148
+ pairs = [(check.not_none(n), p) for n, p in pairs]
149
+
150
+ root = check.single([n for n, p in pairs if p is None]) # noqa
151
+
152
+ children_by_node: ta.MutableMapping[NodeT, ta.MutableSequence[NodeT]] = col.IdentityKeyDict() if identity else {} # noqa
153
+ for n, _ in pairs:
154
+ children_by_node[n] = []
155
+ for n, p in pairs:
156
+ if p is not None:
157
+ children_by_node[p].append(n)
158
+
159
+ return cls(
160
+ root,
161
+ children_by_node.__getitem__,
162
+ identity=identity,
163
+ **kwargs,
164
+ )
165
+
166
+ @classmethod
167
+ def from_children(
168
+ cls,
169
+ src: ta.Union[
170
+ ta.Mapping[NodeT, ta.Iterable[NodeT]],
171
+ ta.Iterable[tuple[NodeT, ta.Iterable[NodeT]]],
172
+ ],
173
+ *,
174
+ identity: bool = False,
175
+ **kwargs
176
+ ) -> 'BasicTreeAnalysis[NodeT]':
177
+ pairs: ta.Sequence[tuple[NodeT, ta.Sequence[NodeT]]]
178
+ if isinstance(src, ta.Mapping):
179
+ pairs = list(src.items()) # type: ignore
180
+ elif isinstance(src, ta.Iterable):
181
+ pairs = list(src) # type: ignore
182
+ else:
183
+ raise TypeError(src)
184
+
185
+ pairs = [(check.not_none(n), [check.not_none(c) for c in cs]) for n, cs in pairs]
186
+
187
+ children_by_node: ta.MutableMapping[NodeT, ta.Sequence[NodeT]] = col.IdentityKeyDict() if identity else {}
188
+ parents_by_node: ta.MutableMapping[NodeT, NodeT] = col.IdentityKeyDict() if identity else {}
189
+ for n, cs in pairs:
190
+ check.not_in(n, children_by_node)
191
+ children_by_node[n] = cs
192
+ for c in cs:
193
+ check.not_in(c, parents_by_node)
194
+ parents_by_node[c] = n
195
+
196
+ e: ta.Any
197
+ d: ta.Any
198
+ if identity:
199
+ e, d = id, col.unique_dict((id(n), n) for n, _ in pairs)
200
+ else:
201
+ e, d = lang.identity, lang.identity
202
+ tsd = {e(n): {e(p)} for n, p in parents_by_node.items()}
203
+ ts = list(col.mut_toposort(tsd))
204
+ root = d(check.single(ts[0]))
205
+
206
+ return cls(
207
+ root,
208
+ children_by_node.__getitem__,
209
+ identity=identity,
210
+ **kwargs,
211
+ )
212
+
213
+ @cached.property
214
+ def _node_sets_by_type(self) -> ta.MutableMapping[type, ta.AbstractSet[NodeT]]:
215
+ return weakref.WeakKeyDictionary()
216
+
217
+ def get_node_type_set(self, ty: type[T]) -> ta.AbstractSet[T]:
218
+ try:
219
+ return self._node_sets_by_type[ty] # type: ignore
220
+ except KeyError:
221
+ ret = self._node_sets_by_type[ty] = self._set_fac(n for n in self.nodes if isinstance(n, ty))
222
+ return ret # type: ignore
223
+
224
+ def iter_ancestors(self, node: NodeT) -> NodeGenerator[NodeT]:
225
+ cur: ta.Optional[NodeT] = node
226
+ while True:
227
+ cur = self.parents_by_node.get(cur) # type: ignore
228
+ if cur is None:
229
+ break
230
+ yield cur
231
+
232
+ def get_lineage(self, node: NodeT) -> col.IndexedSeq[NodeT]:
233
+ return self._idx_seq_fac(reversed([node, *self.iter_ancestors(node)]))
234
+
235
+ def get_first_parent_of_type(self, node: NodeT, ty: type[T]) -> ta.Optional[T]:
236
+ for cur in self.iter_ancestors(node):
237
+ if isinstance(cur, ty):
238
+ return cur
239
+ return None
240
+
241
+ @cached.property
242
+ def depths_by_node(self) -> ta.Mapping[NodeT, int]:
243
+ def rec(n, d):
244
+ dct[n] = d
245
+ for c in self._children_by_node[n]:
246
+ rec(c, d + 1)
247
+ dct: ta.MutableMapping[NodeT, int] = self._dict_fac()
248
+ rec(self._root, 0)
249
+ return dct
File without changes
omlish/http/consts.py ADDED
@@ -0,0 +1,20 @@
1
+ import http # noqa
2
+
3
+
4
+ def format_status(status: http.HTTPStatus) -> str:
5
+ return '%d %s' % (int(status), status.phrase)
6
+
7
+
8
+ STATUS_OK = format_status(http.HTTPStatus.OK)
9
+ STATUS_BAD_REQUEST = format_status(http.HTTPStatus.BAD_REQUEST)
10
+ STATUS_FORBIDDEN = format_status(http.HTTPStatus.FORBIDDEN)
11
+ STATUS_NOT_FOUND = format_status(http.HTTPStatus.NOT_FOUND)
12
+ STATUS_METHOD_NOT_ALLOWED = format_status(http.HTTPStatus.METHOD_NOT_ALLOWED)
13
+
14
+
15
+ HEADER_CONTENT_TYPE = b'Content-Type'
16
+ CONTENT_TYPE_TEXT = b'text/plain'
17
+ CONTENT_TYPE_TEXT_UTF8 = CONTENT_TYPE_TEXT + b'; charset=utf-8'
18
+ CONTENT_TYPE_JSON = b'application/json'
19
+ CONTENT_TYPE_ICON = b'image/x-icon'
20
+ CONTENT_TYPE_BYTES = b'application/octet-stream'
omlish/http/wsgi.py ADDED
@@ -0,0 +1,34 @@
1
+ import typing as ta
2
+
3
+ from .. import lang
4
+
5
+
6
+ Environ = ta.Mapping[str, ta.Any]
7
+ StartResponse = ta.Callable[[str, ta.Iterable[tuple[str | bytes, str | bytes]]], ta.Callable[[lang.BytesLike], None]]
8
+ App = ta.Callable[[Environ, StartResponse], ta.Iterable[lang.BytesLike]]
9
+
10
+
11
+ # class App(lang.Abstract):
12
+ #
13
+ # def __enter__(self: AppT) -> AppT:
14
+ # return self
15
+ #
16
+ # def __exit__(self, exc_type, exc_val, exc_tb) -> None:
17
+ # return None
18
+ #
19
+ # @abc.abstractmethod
20
+ # def __call__(self, environ: Environ, start_response: StartResponse) -> ta.Iterable[bytes]:
21
+ # raise NotImplementedError
22
+
23
+
24
+ # class AsyncApp(lang.Abstract):
25
+ #
26
+ # async def __aenter__(self: AppT) -> AppT:
27
+ # return self
28
+ #
29
+ # async def __aexit__(self, exc_type, exc_val, exc_tb) -> None:
30
+ # return None
31
+ #
32
+ # @abc.abstractmethod
33
+ # async def __call__(self, scope, receive, send) -> ta.Iterable[bytes]:
34
+ # raise NotImplementedError
@@ -0,0 +1,85 @@
1
+ """
2
+ ~> https://github.com/google/guice/commit/70248eafa90cd70a68b293763e53f6aec656e73c
3
+ """
4
+ from .bindings import ( # noqa
5
+ Binding,
6
+ as_,
7
+ as_binding,
8
+ )
9
+
10
+ from .eagers import ( # noqa
11
+ eager,
12
+ )
13
+
14
+ from .elements import ( # noqa
15
+ as_elements,
16
+ Element,
17
+ Elements,
18
+ )
19
+
20
+ from .exceptions import ( # noqa
21
+ CyclicDependencyException,
22
+ DuplicateKeyException,
23
+ KeyException,
24
+ ScopeAlreadyOpenException,
25
+ ScopeException,
26
+ ScopeNotOpenException,
27
+ UnboundKeyException,
28
+ )
29
+
30
+ from .injector import ( # noqa
31
+ create_injector,
32
+ Injector,
33
+ )
34
+
35
+ from .inspect import ( # noqa
36
+ Kwarg,
37
+ KwargsTarget,
38
+ )
39
+
40
+ from .keys import ( # noqa
41
+ Key,
42
+ as_key,
43
+ multi,
44
+ tag,
45
+ )
46
+
47
+ from .managed import ( # noqa
48
+ create_managed_injector,
49
+ )
50
+
51
+ from .overrides import ( # noqa
52
+ override,
53
+ )
54
+
55
+ from .private import ( # noqa
56
+ expose,
57
+ private,
58
+ )
59
+
60
+ from .providers import ( # noqa
61
+ Provider,
62
+ as_provider,
63
+ const,
64
+ ctor,
65
+ fn,
66
+ link,
67
+ )
68
+
69
+ from .scopes import ( # noqa
70
+ ScopeBinding,
71
+ SeededScope,
72
+ Singleton,
73
+ Thread,
74
+ bind_scope,
75
+ bind_scope_seed,
76
+ enter_seeded_scope,
77
+ in_,
78
+ singleton,
79
+ )
80
+
81
+ from .types import ( # noqa
82
+ Cls,
83
+ Scope,
84
+ Unscoped,
85
+ )
@@ -0,0 +1,12 @@
1
+ import typing as ta
2
+
3
+ from .elements import Element
4
+ from .elements import Elements
5
+ from .elements import as_elements
6
+
7
+
8
+ def bind(*args: ta.Any) -> Elements:
9
+ if all(isinstance(a, (Element, Elements)) for a in args):
10
+ return as_elements(*args)
11
+
12
+ raise TypeError(args)
@@ -0,0 +1,49 @@
1
+ import typing as ta
2
+
3
+ from .. import check
4
+ from .. import dataclasses as dc
5
+ from .. import lang
6
+ from .elements import Element
7
+ from .elements import Elements
8
+ from .keys import Key
9
+ from .keys import as_key
10
+ from .providers import Provider
11
+ from .providers import as_provider
12
+ from .providers import const
13
+ from .providers import ctor
14
+ from .providers import fn
15
+ from .types import Scope
16
+ from .types import Unscoped
17
+
18
+
19
+ ##
20
+
21
+
22
+ @dc.dataclass(frozen=True)
23
+ @dc.extra_params(cache_hash=True)
24
+ class Binding(Element, lang.Final):
25
+ key: Key
26
+ provider: Provider
27
+ scope: Scope = Unscoped()
28
+
29
+
30
+ ##
31
+
32
+
33
+ def as_binding(o: ta.Any) -> Binding:
34
+ check.not_none(o)
35
+ if isinstance(o, Binding):
36
+ return o
37
+ check.not_isinstance(o, (Element, Elements))
38
+ if isinstance(o, Provider):
39
+ return Binding(Key(check.not_none(o.provided_cls())), o) # type: ignore # noqa
40
+ if isinstance(o, type):
41
+ return as_binding(ctor(o))
42
+ if callable(o):
43
+ return as_binding(fn(o))
44
+ cls = type(o)
45
+ return Binding(Key(cls), const(o, cls))
46
+
47
+
48
+ def as_(k: ta.Any, p: ta.Any) -> Binding:
49
+ return Binding(as_key(k), as_provider(p))
@@ -0,0 +1,21 @@
1
+ """
2
+ TODO:
3
+ - SCOPED - eagers for EACH SCOPE
4
+ """
5
+ import typing as ta
6
+
7
+ from .. import dataclasses as dc
8
+ from .. import lang
9
+ from .elements import Element
10
+ from .keys import Key
11
+ from .keys import as_key
12
+
13
+
14
+ @dc.dataclass(frozen=True)
15
+ @dc.extra_params(cache_hash=True)
16
+ class Eager(Element, lang.Final):
17
+ key: Key
18
+
19
+
20
+ def eager(k: ta.Any) -> Element:
21
+ return Eager(as_key(k))
@@ -0,0 +1,43 @@
1
+ """
2
+ TODO:
3
+ - as_element[s] - universal
4
+ """
5
+ import typing as ta
6
+
7
+ from .. import dataclasses as dc
8
+ from .. import lang
9
+
10
+
11
+ class Element(lang.Abstract):
12
+ pass
13
+
14
+
15
+ @dc.dataclass(frozen=True)
16
+ class Elements(lang.Final):
17
+ es: frozenset[Element] | None = None
18
+ cs: frozenset['Elements'] | None = None
19
+
20
+ def __iter__(self) -> ta.Generator[Element, None, None]:
21
+ if self.es:
22
+ yield from self.es
23
+ if self.cs:
24
+ for c in self.cs:
25
+ yield from c
26
+
27
+
28
+ def as_elements(*args: ta.Union[Element, Elements]) -> Elements:
29
+ es: set[Element] = set()
30
+ cs: set['Elements'] = set()
31
+ for a in args:
32
+ if isinstance(a, Element):
33
+ es.add(a)
34
+ elif isinstance(a, Elements):
35
+ cs.add(a)
36
+ else:
37
+ raise TypeError(a)
38
+ if not es and len(cs) == 1:
39
+ return next(iter(cs))
40
+ return Elements(
41
+ frozenset(es) if es else None,
42
+ frozenset(cs) if cs else None,
43
+ )
@@ -0,0 +1,49 @@
1
+ import typing as ta
2
+
3
+ from .. import dataclasses as dc
4
+ from .keys import Key
5
+ from .types import Scope
6
+
7
+
8
+ ##
9
+
10
+
11
+ @dc.dataclass()
12
+ class KeyException(Exception):
13
+ key: Key
14
+
15
+ source: ta.Any = None
16
+ name: ta.Optional[str] = None
17
+
18
+
19
+ @dc.dataclass()
20
+ class UnboundKeyException(KeyException):
21
+ pass
22
+
23
+
24
+ @dc.dataclass()
25
+ class DuplicateKeyException(KeyException):
26
+ pass
27
+
28
+
29
+ @dc.dataclass()
30
+ class CyclicDependencyException(KeyException):
31
+ pass
32
+
33
+
34
+ ##
35
+
36
+
37
+ @dc.dataclass()
38
+ class ScopeException(Exception):
39
+ scope: Scope
40
+
41
+
42
+ @dc.dataclass()
43
+ class ScopeAlreadyOpenException(ScopeException):
44
+ pass
45
+
46
+
47
+ @dc.dataclass()
48
+ class ScopeNotOpenException(ScopeException):
49
+ pass
File without changes
@@ -0,0 +1,19 @@
1
+ from ... import dataclasses as dc
2
+ from ... import lang
3
+ from ..bindings import Binding
4
+ from ..keys import Key
5
+ from ..types import Scope
6
+ from ..types import Unscoped
7
+ from .providers import ProviderImpl
8
+
9
+
10
+ ##
11
+
12
+
13
+ @dc.dataclass(frozen=True, eq=False)
14
+ @dc.extra_params(cache_hash=True)
15
+ class BindingImpl(lang.Final):
16
+ key: Key
17
+ provider: ProviderImpl
18
+ scope: Scope = Unscoped()
19
+ binding: Binding | None = None