omlish 0.0.0.dev339__py3-none-any.whl → 0.0.0.dev341__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.
Files changed (40) hide show
  1. omlish/__about__.py +2 -2
  2. omlish/asyncs/bluelet/LICENSE +1 -1
  3. omlish/asyncs/bluelet/api.py +1 -1
  4. omlish/asyncs/bluelet/core.py +1 -1
  5. omlish/asyncs/bluelet/events.py +1 -1
  6. omlish/asyncs/bluelet/files.py +1 -1
  7. omlish/asyncs/bluelet/runner.py +1 -1
  8. omlish/asyncs/bluelet/sockets.py +1 -1
  9. omlish/check.py +197 -30
  10. omlish/collections/__init__.py +19 -0
  11. omlish/collections/multimaps.py +151 -0
  12. omlish/formats/json/__init__.py +13 -13
  13. omlish/formats/json/backends/__init__.py +2 -2
  14. omlish/formats/json/backends/default.py +56 -12
  15. omlish/formats/json/backends/orjson.py +6 -5
  16. omlish/formats/json/backends/std.py +4 -1
  17. omlish/formats/json/backends/ujson.py +6 -5
  18. omlish/formats/json/codecs.py +4 -4
  19. omlish/graphs/dags.py +112 -48
  20. omlish/graphs/domination.py +5 -1
  21. omlish/graphs/dot/items.py +3 -0
  22. omlish/graphs/dot/make.py +3 -0
  23. omlish/graphs/dot/rendering.py +3 -0
  24. omlish/graphs/dot/utils.py +3 -0
  25. omlish/graphs/trees.py +5 -4
  26. omlish/lang/classes/bindable.py +2 -0
  27. omlish/lite/check.py +6 -6
  28. omlish/math/__init__.py +15 -15
  29. omlish/math/fixed.py +25 -15
  30. omlish/os/forkhooks.py +4 -4
  31. omlish/typedvalues/__init__.py +4 -0
  32. omlish/typedvalues/collection.py +3 -0
  33. omlish/typedvalues/consumer.py +12 -0
  34. {omlish-0.0.0.dev339.dist-info → omlish-0.0.0.dev341.dist-info}/METADATA +1 -1
  35. {omlish-0.0.0.dev339.dist-info → omlish-0.0.0.dev341.dist-info}/RECORD +39 -39
  36. omlish/formats/json/json.py +0 -17
  37. {omlish-0.0.0.dev339.dist-info → omlish-0.0.0.dev341.dist-info}/WHEEL +0 -0
  38. {omlish-0.0.0.dev339.dist-info → omlish-0.0.0.dev341.dist-info}/entry_points.txt +0 -0
  39. {omlish-0.0.0.dev339.dist-info → omlish-0.0.0.dev341.dist-info}/licenses/LICENSE +0 -0
  40. {omlish-0.0.0.dev339.dist-info → omlish-0.0.0.dev341.dist-info}/top_level.txt +0 -0
@@ -1,9 +1,9 @@
1
1
  from ..codecs import make_object_lazy_loaded_codec
2
2
  from ..codecs import make_str_object_codec
3
- from .json import dumps
4
- from .json import dumps_compact
5
- from .json import dumps_pretty
6
- from .json import loads
3
+ from .backends.default import dumps
4
+ from .backends.default import dumps_compact
5
+ from .backends.default import dumps_pretty
6
+ from .backends.default import loads
7
7
 
8
8
 
9
9
  ##
omlish/graphs/dags.py CHANGED
@@ -12,100 +12,164 @@ from .. import check
12
12
  from .. import lang
13
13
 
14
14
 
15
- K = ta.TypeVar('K')
16
- V = ta.TypeVar('V')
17
15
  T = ta.TypeVar('T')
18
- U = ta.TypeVar('U')
19
16
 
20
17
 
21
- def traverse_links(data: ta.Mapping[T, ta.Iterable[T]], keys: ta.Iterable[T]) -> set[T]:
22
- keys = set(keys)
23
- todo = set(keys)
18
+ ##
19
+
20
+
21
+ class LinkError(KeyError):
22
+ pass
23
+
24
+
25
+ def traverse_links(
26
+ links: ta.Mapping[T, ta.Iterable[T]],
27
+ roots: ta.Iterable[T],
28
+ *,
29
+ include_roots: bool = False,
30
+ strict: bool = False,
31
+ ) -> set[T]:
32
+ """Returns all keys deeply reachable from given roots. Handles cycles."""
33
+
34
+ roots = set(roots)
35
+
36
+ todo = set(roots)
24
37
  seen: set[T] = set()
25
38
  while todo:
26
39
  key = todo.pop()
27
40
  seen.add(key)
28
- cur = data.get(key, [])
29
- todo.update(set(cur) - seen)
30
- return seen - keys
31
-
32
41
 
33
- def invert_set_map(src: ta.Mapping[K, ta.Iterable[V]]) -> dict[V, set[K]]:
34
- dst: dict[V, set[K]] = {}
35
- for l, rs in src.items():
36
- for r in rs:
42
+ try:
43
+ cur = links[key]
44
+ except KeyError:
45
+ if strict:
46
+ raise LinkError(key) from None
47
+ else:
48
+ todo.update(set(cur) - seen)
49
+
50
+ if include_roots:
51
+ return seen
52
+ else:
53
+ return seen - roots
54
+
55
+
56
+ def invert_links(
57
+ links: ta.Mapping[T, ta.Iterable[T]],
58
+ *,
59
+ auto_add_roots: bool = False,
60
+ if_absent: ta.Literal['raise', 'ignore', 'add'] = 'add',
61
+ ) -> dict[T, set[T]]:
62
+ check.in_(if_absent, ('raise', 'ignore', 'add'))
63
+ if if_absent != 'add':
64
+ check.arg(auto_add_roots, 'auto_add_roots must be True with given if_absent is not "add"')
65
+
66
+ ret: dict[T, set[T]]
67
+ if auto_add_roots:
68
+ ret = {src: set() for src in links}
69
+ else:
70
+ ret = {}
71
+
72
+ for src, dsts in links.items():
73
+ for dst in dsts:
37
74
  try:
38
- s = dst[r]
75
+ tgt = ret[dst]
39
76
  except KeyError:
40
- s = dst[r] = set()
41
- s.add(l)
42
- return dst
77
+ if if_absent == 'raise':
78
+ raise LinkError(dst) from None
79
+ elif if_absent == 'ignore':
80
+ continue
81
+ elif if_absent == 'add':
82
+ tgt = ret[dst] = set()
83
+ else:
84
+ raise RuntimeError from None
85
+
86
+ tgt.add(src)
43
87
 
88
+ return ret
44
89
 
45
- def invert_symmetric_set_map(src: ta.Mapping[T, ta.Iterable[T]]) -> dict[T, set[T]]:
46
- dst: dict[T, set[T]] = {l: set() for l in src}
47
- for l, rs in src.items():
48
- for r in rs:
49
- dst[r].add(l)
50
- return dst
90
+
91
+ ##
51
92
 
52
93
 
53
94
  class Dag(ta.Generic[T]):
54
- def __init__(self, input_its_by_outputs: ta.Mapping[T, ta.Iterable[T]]) -> None:
95
+ """Given 'input_its_by_outputs', or a map from nodes to that node's dependencies."""
96
+
97
+ def __init__(
98
+ self,
99
+ input_its_by_outputs: ta.Mapping[T, ta.Iterable[T]],
100
+ *,
101
+ auto_add_outputs: bool = True,
102
+ if_absent: ta.Literal['raise', 'ignore', 'add'] = 'add',
103
+ ) -> None:
55
104
  super().__init__()
56
105
 
57
106
  self._input_sets_by_output = {u: set(d) for u, d in input_its_by_outputs.items()}
58
107
 
108
+ self._output_sets_by_input = invert_links(
109
+ self._input_sets_by_output,
110
+ auto_add_roots=auto_add_outputs,
111
+ if_absent=if_absent,
112
+ )
113
+
59
114
  @property
60
115
  def input_sets_by_output(self) -> ta.Mapping[T, ta.AbstractSet[T]]:
61
116
  return self._input_sets_by_output
62
117
 
63
- @lang.cached_property
118
+ @property
64
119
  def output_sets_by_input(self) -> ta.Mapping[T, ta.AbstractSet[T]]:
65
- return invert_symmetric_set_map(self._input_sets_by_output)
120
+ return self._output_sets_by_input
66
121
 
67
- def subdag(self, *args, **kwargs) -> 'Subdag[T]':
68
- return Subdag(self, *args, **kwargs)
122
+ def subdag(
123
+ self,
124
+ roots: ta.Iterable[T],
125
+ *,
126
+ ignored: ta.Iterable[T] | None = None,
127
+ ) -> 'Subdag[T]':
128
+ return Subdag(
129
+ self,
130
+ roots,
131
+ ignored=ignored,
132
+ )
69
133
 
70
134
 
71
- class Subdag(ta.Generic[U]):
135
+ class Subdag(ta.Generic[T]):
72
136
  def __init__(
73
137
  self,
74
- dag: 'Dag[U]',
75
- targets: ta.Iterable[U],
138
+ dag: Dag[T],
139
+ roots: ta.Iterable[T],
76
140
  *,
77
- ignored: ta.Iterable[U] | None = None,
141
+ ignored: ta.Iterable[T] | None = None,
78
142
  ) -> None:
79
143
  super().__init__()
80
144
 
81
- self._dag: Dag[U] = check.isinstance(dag, Dag)
82
- self._targets = set(targets)
83
- self._ignored = set(ignored or []) - self._targets
145
+ self._dag: Dag[T] = check.isinstance(dag, Dag)
146
+ self._roots = set(roots)
147
+ self._ignored = set(ignored or []) - self._roots
84
148
 
85
149
  @property
86
- def dag(self) -> 'Dag[U]':
150
+ def dag(self) -> Dag[T]:
87
151
  return self._dag
88
152
 
89
153
  @property
90
- def targets(self) -> ta.AbstractSet[U]:
91
- return self._targets
154
+ def roots(self) -> ta.AbstractSet[T]:
155
+ return self._roots
92
156
 
93
157
  @property
94
- def ignored(self) -> ta.AbstractSet[U]:
158
+ def ignored(self) -> ta.AbstractSet[T]:
95
159
  return self._ignored
96
160
 
97
161
  @lang.cached_property
98
- def inputs(self) -> ta.AbstractSet[U]:
99
- return traverse_links(self.dag.input_sets_by_output, self.targets) - self.ignored
162
+ def inputs(self) -> ta.AbstractSet[T]:
163
+ return traverse_links(self._dag.input_sets_by_output, self._roots) - self._ignored
100
164
 
101
165
  @lang.cached_property
102
- def outputs(self) -> ta.AbstractSet[U]:
103
- return traverse_links(self.dag.output_sets_by_input, self.targets) - self.ignored
166
+ def outputs(self) -> ta.AbstractSet[T]:
167
+ return traverse_links(self._dag.output_sets_by_input, self._roots) - self._ignored
104
168
 
105
169
  @lang.cached_property
106
- def output_inputs(self) -> ta.AbstractSet[U]:
107
- return traverse_links(self.dag.input_sets_by_output, self.outputs) - self.ignored
170
+ def output_inputs(self) -> ta.AbstractSet[T]:
171
+ return traverse_links(self._dag.input_sets_by_output, self.outputs) - self._ignored
108
172
 
109
173
  @lang.cached_property
110
- def all(self) -> ta.AbstractSet[U]:
111
- return self.targets | self.inputs | self.outputs | self.output_inputs
174
+ def all(self) -> ta.AbstractSet[T]:
175
+ return self.roots | self.inputs | self.outputs | self.output_inputs
@@ -9,7 +9,11 @@ from .. import lang
9
9
  V = ta.TypeVar('V')
10
10
  MK = ta.TypeVar('MK')
11
11
  MV = ta.TypeVar('MV')
12
- SetMap = ta.Mapping[MK, ta.AbstractSet[MV]]
12
+
13
+ SetMap: ta.TypeAlias = ta.Mapping[MK, ta.AbstractSet[MV]]
14
+
15
+
16
+ ##
13
17
 
14
18
 
15
19
  class DirectedGraph(ta.Generic[V], lang.Abstract):
@@ -12,6 +12,9 @@ from ... import dataclasses as dc
12
12
  from ... import lang
13
13
 
14
14
 
15
+ ##
16
+
17
+
15
18
  class Item(dc.Frozen, lang.Abstract, lang.Sealed):
16
19
  pass
17
20
 
omlish/graphs/dot/make.py CHANGED
@@ -9,6 +9,9 @@ from .items import Node
9
9
  T = ta.TypeVar('T')
10
10
 
11
11
 
12
+ ##
13
+
14
+
12
15
  def make_simple(graph: ta.Mapping[T, ta.Iterable[T]]) -> Graph:
13
16
  return Graph([
14
17
  *[Node(n) for n in {*graph, *lang.flatten(graph.values())}],
@@ -20,6 +20,9 @@ from .items import Table
20
20
  from .items import Text
21
21
 
22
22
 
23
+ ##
24
+
25
+
23
26
  class Renderer:
24
27
  def __init__(self, out: ta.TextIO) -> None:
25
28
  super().__init__()
@@ -2,6 +2,9 @@ import html
2
2
  import typing as ta
3
3
 
4
4
 
5
+ ##
6
+
7
+
5
8
  def escape(s: str) -> str:
6
9
  return html.escape(s).replace('@', '@')
7
10
 
omlish/graphs/trees.py CHANGED
@@ -10,13 +10,14 @@ from .. import cached
10
10
  from .. import check
11
11
  from .. import collections as col
12
12
  from .. import lang
13
- from ..algorithm import all as alg
13
+ from ..algorithm.toposort import mut_toposort
14
14
 
15
15
 
16
16
  T = ta.TypeVar('T')
17
17
  NodeT = ta.TypeVar('NodeT')
18
- NodeWalker = ta.Callable[[NodeT], ta.Iterable[NodeT]]
19
- NodeGenerator = ta.Generator[NodeT, None, None]
18
+
19
+ NodeWalker: ta.TypeAlias = ta.Callable[[NodeT], ta.Iterable[NodeT]]
20
+ NodeGenerator: ta.TypeAlias = ta.Generator[NodeT, None, None]
20
21
 
21
22
 
22
23
  ##
@@ -200,7 +201,7 @@ class BasicTreeAnalysis(ta.Generic[NodeT]):
200
201
  else:
201
202
  e, d = lang.identity, lang.identity
202
203
  tsd = {e(n): {e(p)} for n, p in parents_by_node.items()}
203
- ts = list(alg.mut_toposort(tsd))
204
+ ts = list(mut_toposort(tsd))
204
205
  root = d(check.single(ts[0]))
205
206
 
206
207
  return cls(
@@ -27,6 +27,8 @@ class BindableClass(ta.Generic[T]):
27
27
  setattr(self, '_bound', _bound)
28
28
 
29
29
  def __class_getitem__(cls, *args, **kwargs):
30
+ # FIXME: this could handle __mro_items__ to be subclassable, but it's not currently really intended to be
31
+ # subclassed
30
32
  if cls is BindableClass:
31
33
  return super().__class_getitem__(*args, **kwargs) # type: ignore[misc]
32
34
 
omlish/lite/check.py CHANGED
@@ -177,7 +177,7 @@ class Checks:
177
177
 
178
178
  return inner
179
179
 
180
- def cast(self, v: ta.Any, cls: ta.Type[T], msg: CheckMessage = None) -> T: # noqa
180
+ def cast(self, v: ta.Any, cls: ta.Type[T], msg: CheckMessage = None) -> T:
181
181
  if not isinstance(v, cls):
182
182
  self._raise(
183
183
  TypeError,
@@ -226,7 +226,7 @@ class Checks:
226
226
 
227
227
  return v
228
228
 
229
- def not_issubclass(self, v: ta.Type[T], spec: ta.Any, msg: CheckMessage = None) -> ta.Type[T]: # noqa
229
+ def not_issubclass(self, v: ta.Type[T], spec: ta.Any, msg: CheckMessage = None) -> ta.Type[T]:
230
230
  if issubclass(v, spec):
231
231
  self._raise(
232
232
  TypeError,
@@ -317,21 +317,21 @@ class Checks:
317
317
 
318
318
  return it
319
319
 
320
- def single(self, obj: ta.Iterable[T], message: CheckMessage = None) -> T:
320
+ def single(self, obj: ta.Iterable[T], msg: CheckMessage = None) -> T:
321
321
  try:
322
322
  [value] = obj
323
323
  except ValueError:
324
324
  self._raise(
325
325
  ValueError,
326
326
  'Must be single',
327
- message,
327
+ msg,
328
328
  Checks._ArgsKwargs(obj),
329
329
  render_fmt='%s',
330
330
  )
331
331
 
332
332
  return value
333
333
 
334
- def opt_single(self, obj: ta.Iterable[T], message: CheckMessage = None) -> ta.Optional[T]:
334
+ def opt_single(self, obj: ta.Iterable[T], msg: CheckMessage = None) -> ta.Optional[T]:
335
335
  it = iter(obj)
336
336
  try:
337
337
  value = next(it)
@@ -346,7 +346,7 @@ class Checks:
346
346
  self._raise(
347
347
  ValueError,
348
348
  'Must be empty or single',
349
- message,
349
+ msg,
350
350
  Checks._ArgsKwargs(obj),
351
351
  render_fmt='%s',
352
352
  )
omlish/math/__init__.py CHANGED
@@ -35,11 +35,11 @@ from .fixed import ( # noqa
35
35
  CheckedInt64,
36
36
  CheckedInt128,
37
37
 
38
- CheckedUInt8,
39
- CheckedUInt16,
40
- CheckedUInt32,
41
- CheckedUInt64,
42
- CheckedUInt128,
38
+ CheckedUint8,
39
+ CheckedUint16,
40
+ CheckedUint32,
41
+ CheckedUint64,
42
+ CheckedUint128,
43
43
 
44
44
  ClampedInt8,
45
45
  ClampedInt16,
@@ -47,11 +47,11 @@ from .fixed import ( # noqa
47
47
  ClampedInt64,
48
48
  ClampedInt128,
49
49
 
50
- ClampedUInt8,
51
- ClampedUInt16,
52
- ClampedUInt32,
53
- ClampedUInt64,
54
- ClampedUInt128,
50
+ ClampedUint8,
51
+ ClampedUint16,
52
+ ClampedUint32,
53
+ ClampedUint64,
54
+ ClampedUint128,
55
55
 
56
56
  WrappedInt8,
57
57
  WrappedInt16,
@@ -59,11 +59,11 @@ from .fixed import ( # noqa
59
59
  WrappedInt64,
60
60
  WrappedInt128,
61
61
 
62
- WrappedUInt8,
63
- WrappedUInt16,
64
- WrappedUInt32,
65
- WrappedUInt64,
66
- WrappedUInt128,
62
+ WrappedUint8,
63
+ WrappedUint16,
64
+ WrappedUint32,
65
+ WrappedUint64,
66
+ WrappedUint128,
67
67
  )
68
68
 
69
69
  from .floats import ( # noqa
omlish/math/fixed.py CHANGED
@@ -183,6 +183,16 @@ class FixedWidthInt(int, lang.Abstract):
183
183
  locals()[_proxy_name] = _gen_tuple_proxy_method(_proxy_name)
184
184
  del _proxy_name
185
185
 
186
+ #
187
+
188
+ def __invert__(self) -> ta.Self:
189
+ if not self.SIGNED:
190
+ return self.__class__(~int(self) & self.MASK)
191
+ else:
192
+ return self.__class__(super().__invert__())
193
+
194
+ #
195
+
186
196
  def __repr__(self) -> str:
187
197
  return f'{self.__class__.__name__}({int(self)})'
188
198
 
@@ -278,23 +288,23 @@ class CheckedInt128(CheckedInt, SignedInt, AnyInt128):
278
288
  #
279
289
 
280
290
 
281
- class CheckedUInt8(CheckedInt, UnsignedInt, AnyInt8):
291
+ class CheckedUint8(CheckedInt, UnsignedInt, AnyInt8):
282
292
  pass
283
293
 
284
294
 
285
- class CheckedUInt16(CheckedInt, UnsignedInt, AnyInt16):
295
+ class CheckedUint16(CheckedInt, UnsignedInt, AnyInt16):
286
296
  pass
287
297
 
288
298
 
289
- class CheckedUInt32(CheckedInt, UnsignedInt, AnyInt32):
299
+ class CheckedUint32(CheckedInt, UnsignedInt, AnyInt32):
290
300
  pass
291
301
 
292
302
 
293
- class CheckedUInt64(CheckedInt, UnsignedInt, AnyInt64):
303
+ class CheckedUint64(CheckedInt, UnsignedInt, AnyInt64):
294
304
  pass
295
305
 
296
306
 
297
- class CheckedUInt128(CheckedInt, UnsignedInt, AnyInt128):
307
+ class CheckedUint128(CheckedInt, UnsignedInt, AnyInt128):
298
308
  pass
299
309
 
300
310
 
@@ -324,23 +334,23 @@ class ClampedInt128(ClampedInt, SignedInt, AnyInt128):
324
334
  #
325
335
 
326
336
 
327
- class ClampedUInt8(ClampedInt, UnsignedInt, AnyInt8):
337
+ class ClampedUint8(ClampedInt, UnsignedInt, AnyInt8):
328
338
  pass
329
339
 
330
340
 
331
- class ClampedUInt16(ClampedInt, UnsignedInt, AnyInt16):
341
+ class ClampedUint16(ClampedInt, UnsignedInt, AnyInt16):
332
342
  pass
333
343
 
334
344
 
335
- class ClampedUInt32(ClampedInt, UnsignedInt, AnyInt32):
345
+ class ClampedUint32(ClampedInt, UnsignedInt, AnyInt32):
336
346
  pass
337
347
 
338
348
 
339
- class ClampedUInt64(ClampedInt, UnsignedInt, AnyInt64):
349
+ class ClampedUint64(ClampedInt, UnsignedInt, AnyInt64):
340
350
  pass
341
351
 
342
352
 
343
- class ClampedUInt128(ClampedInt, UnsignedInt, AnyInt128):
353
+ class ClampedUint128(ClampedInt, UnsignedInt, AnyInt128):
344
354
  pass
345
355
 
346
356
 
@@ -370,21 +380,21 @@ class WrappedInt128(WrappedInt, SignedInt, AnyInt128):
370
380
  #
371
381
 
372
382
 
373
- class WrappedUInt8(WrappedInt, UnsignedInt, AnyInt8):
383
+ class WrappedUint8(WrappedInt, UnsignedInt, AnyInt8):
374
384
  pass
375
385
 
376
386
 
377
- class WrappedUInt16(WrappedInt, UnsignedInt, AnyInt16):
387
+ class WrappedUint16(WrappedInt, UnsignedInt, AnyInt16):
378
388
  pass
379
389
 
380
390
 
381
- class WrappedUInt32(WrappedInt, UnsignedInt, AnyInt32):
391
+ class WrappedUint32(WrappedInt, UnsignedInt, AnyInt32):
382
392
  pass
383
393
 
384
394
 
385
- class WrappedUInt64(WrappedInt, UnsignedInt, AnyInt64):
395
+ class WrappedUint64(WrappedInt, UnsignedInt, AnyInt64):
386
396
  pass
387
397
 
388
398
 
389
- class WrappedUInt128(WrappedInt, UnsignedInt, AnyInt128):
399
+ class WrappedUint128(WrappedInt, UnsignedInt, AnyInt128):
390
400
  pass
omlish/os/forkhooks.py CHANGED
@@ -36,9 +36,9 @@ class _ForkHookManager:
36
36
 
37
37
  #
38
38
 
39
- _hooks_by_key: ta.ClassVar[ta.Dict[str, Hook]] = {}
39
+ _hooks_by_key: ta.ClassVar[ta.Dict[ta.Any, Hook]] = {}
40
40
 
41
- _hook_keys: ta.ClassVar[ta.FrozenSet[str]] = frozenset()
41
+ _hook_keys: ta.ClassVar[ta.FrozenSet[ta.Any]] = frozenset()
42
42
  _priority_ordered_hooks: ta.ClassVar[ta.List[Hook]] = []
43
43
 
44
44
  @classmethod
@@ -191,7 +191,7 @@ class ForkHook(abc.ABC): # noqa
191
191
  ##
192
192
 
193
193
 
194
- class _ForkDepthTracker(ForkHook):
194
+ class ForkDepthTracker(ForkHook):
195
195
  _hook_priority = -1000
196
196
 
197
197
  _fork_depth: ta.ClassVar[int] = 0
@@ -208,7 +208,7 @@ class _ForkDepthTracker(ForkHook):
208
208
 
209
209
 
210
210
  def get_fork_depth() -> int:
211
- return _ForkDepthTracker.get_fork_depth()
211
+ return ForkDepthTracker.get_fork_depth()
212
212
 
213
213
 
214
214
  ##
@@ -6,12 +6,16 @@ from .collection import ( # noqa
6
6
  DuplicateUniqueTypedValueError,
7
7
 
8
8
  TypedValues,
9
+
10
+ collect,
9
11
  )
10
12
 
11
13
  from .consumer import ( # noqa
12
14
  UnconsumedTypedValuesError,
13
15
 
14
16
  TypedValuesConsumer,
17
+
18
+ consume,
15
19
  )
16
20
 
17
21
  from .generic import ( # noqa
@@ -205,3 +205,6 @@ class TypedValues(
205
205
  ret = tuple(tv for tv in self if isinstance(tv, cls))
206
206
  any_dct[cls] = ret
207
207
  return ret
208
+
209
+
210
+ collect = TypedValues
@@ -173,3 +173,15 @@ class TypedValuesConsumer(ta.Generic[TypedValueT]):
173
173
  continue
174
174
  dct[k] = v.v # type: ignore[attr-defined]
175
175
  return dct
176
+
177
+
178
+ def consume(
179
+ *tvs: TypedValueT,
180
+ override: bool = False,
181
+ check_type: type | tuple[type, ...] | None = None,
182
+ ) -> TypedValuesConsumer[TypedValueT]:
183
+ return tvc.TypedValues(
184
+ *tvs,
185
+ override=override,
186
+ check_type=check_type,
187
+ ).consume()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: omlish
3
- Version: 0.0.0.dev339
3
+ Version: 0.0.0.dev341
4
4
  Summary: omlish
5
5
  Author: wrmsr
6
6
  License: BSD-3-Clause