omlish 0.0.0.dev493__py3-none-any.whl → 0.0.0.dev506__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 (55) hide show
  1. omlish/CODESTYLE.md +345 -0
  2. omlish/README.md +2 -2
  3. omlish/__about__.py +6 -4
  4. omlish/_check.cc +209 -0
  5. omlish/check.py +11 -0
  6. omlish/dataclasses/__init__.py +4 -0
  7. omlish/dataclasses/impl/concerns/frozen.py +4 -1
  8. omlish/dataclasses/tools/replace.py +27 -0
  9. omlish/dispatch/functions.py +1 -1
  10. omlish/formats/json/stream/lexing.py +13 -5
  11. omlish/formats/json/stream/parsing.py +1 -1
  12. omlish/inject/README.md +430 -0
  13. omlish/inject/__init__.py +1 -0
  14. omlish/inject/_dataclasses.py +64 -64
  15. omlish/inject/eagers.py +0 -4
  16. omlish/inject/elements.py +4 -0
  17. omlish/inject/helpers/late.py +1 -1
  18. omlish/inject/helpers/managed.py +27 -24
  19. omlish/inject/impl/injector.py +7 -22
  20. omlish/inject/impl/inspect.py +0 -8
  21. omlish/inject/impl/origins.py +1 -0
  22. omlish/inject/impl/privates.py +2 -6
  23. omlish/inject/impl/providers.py +0 -4
  24. omlish/inject/impl/scopes.py +14 -18
  25. omlish/inject/inspect.py +9 -0
  26. omlish/inject/multis.py +0 -3
  27. omlish/inject/scopes.py +7 -5
  28. omlish/io/buffers.py +35 -8
  29. omlish/lang/__init__.py +8 -0
  30. omlish/lang/classes/simple.py +2 -1
  31. omlish/lang/iterables.py +6 -0
  32. omlish/lang/objects.py +13 -0
  33. omlish/lang/outcomes.py +1 -1
  34. omlish/lang/recursion.py +1 -1
  35. omlish/lang/sequences.py +33 -0
  36. omlish/lifecycles/_dataclasses.py +18 -18
  37. omlish/lifecycles/injection.py +4 -4
  38. omlish/lite/maybes.py +7 -0
  39. omlish/lite/typing.py +15 -0
  40. omlish/logs/all.py +11 -0
  41. omlish/logs/base.py +3 -3
  42. omlish/logs/bisync.py +99 -0
  43. omlish/marshal/_dataclasses.py +32 -32
  44. omlish/specs/jmespath/_dataclasses.py +38 -38
  45. omlish/specs/jsonschema/keywords/_dataclasses.py +24 -24
  46. omlish/typedvalues/_collection.cc +500 -0
  47. omlish/typedvalues/collection.py +159 -62
  48. omlish/typedvalues/generic.py +5 -4
  49. omlish/typedvalues/values.py +6 -0
  50. {omlish-0.0.0.dev493.dist-info → omlish-0.0.0.dev506.dist-info}/METADATA +9 -7
  51. {omlish-0.0.0.dev493.dist-info → omlish-0.0.0.dev506.dist-info}/RECORD +55 -50
  52. {omlish-0.0.0.dev493.dist-info → omlish-0.0.0.dev506.dist-info}/WHEEL +0 -0
  53. {omlish-0.0.0.dev493.dist-info → omlish-0.0.0.dev506.dist-info}/entry_points.txt +0 -0
  54. {omlish-0.0.0.dev493.dist-info → omlish-0.0.0.dev506.dist-info}/licenses/LICENSE +0 -0
  55. {omlish-0.0.0.dev493.dist-info → omlish-0.0.0.dev506.dist-info}/top_level.txt +0 -0
@@ -1,21 +1,3 @@
1
- """
2
- TODO:
3
- - ** can currently bind in a child/private scope shadowing an external parent binding **
4
- - better source tracking
5
- - scope bindings, auto in root
6
- - injector-internal / blacklisted bindings (Injector itself, default scopes) without rebuilding ElementCollection
7
- - config - proxies, impl select, etc
8
- - config is probably shared with ElementCollection... but not 'bound', must be shared everywhere
9
- - InjectorRoot object?
10
- - ** eagers in any scope, on scope init/open
11
- - unions - raise on ambiguous - usecase: sql.AsyncEngineLike
12
- - multiple live request scopes on single injector - use private injectors?
13
- - more listeners - UnboundKeyListener
14
- - lazy parent listener chain cache thing
15
- - https://github.com/7mind/izumi-chibi-ts
16
- - Axis tagging for conditional bindings (e.g., dev vs prod implementations)
17
- - Fail-fast validation with circular and missing dependency detection
18
- """
19
1
  import contextlib
20
2
  import functools
21
3
  import itertools
@@ -96,6 +78,9 @@ class AsyncInjectorImpl(AsyncInjector, lang.Final):
96
78
  )
97
79
  }
98
80
 
81
+ if self._p is not None:
82
+ self._p._add_child(self) # noqa
83
+
99
84
  _cs: weakref.WeakSet['AsyncInjectorImpl'] | None = None # noqa
100
85
 
101
86
  __cur_req: ta.Optional['AsyncInjectorImpl._Request'] = None
@@ -126,8 +111,8 @@ class AsyncInjectorImpl(AsyncInjector, lang.Final):
126
111
  def get_scope_impl(self, sc: Scope) -> ScopeImpl:
127
112
  return self._scopes[sc]
128
113
 
129
- def create_child(self, ec: ElementCollection) -> AsyncInjector:
130
- c = AsyncInjectorImpl(ec, self)
114
+ def _add_child(self, c: 'AsyncInjectorImpl') -> AsyncInjector:
115
+ check.isinstance(c, AsyncInjectorImpl)
131
116
  if self._cs is None:
132
117
  self._cs = weakref.WeakSet()
133
118
  self._cs.add(c)
@@ -260,7 +245,7 @@ class AsyncInjectorImpl(AsyncInjector, lang.Final):
260
245
  return obj(**kws)
261
246
 
262
247
 
263
- async def create_async_injector(ce: CollectedElements) -> AsyncInjector:
264
- i = AsyncInjectorImpl(ce)
248
+ async def create_async_injector(ce: CollectedElements, p: AsyncInjector | None = None) -> AsyncInjector:
249
+ i = AsyncInjectorImpl(ce, check.isinstance(p, (AsyncInjectorImpl, None)))
265
250
  await i._init() # noqa
266
251
  return i
@@ -1,11 +1,3 @@
1
- """
2
- TODO:
3
- - cache kwarg_keys
4
- - tag annotations? x: ta.Annotated[int, inj.Tag('foo')]
5
- - tag decorator - @inj.tag(x='foo')
6
- - *unpack optional here*
7
- - use ...metadata
8
- """
9
1
  import dataclasses as dc
10
2
  import inspect
11
3
  import typing as ta
@@ -21,6 +21,7 @@ ORIGIN_BASE_OFS = 2
21
21
  ORIGIN_IGNORED_PACKAGES = frozenset([
22
22
  __package__,
23
23
  __package__.rpartition('.')[0],
24
+ __package__.rpartition('.')[0] + '.helpers',
24
25
 
25
26
  lang.__name__,
26
27
  lang.functions.__name__,
@@ -1,12 +1,7 @@
1
- """
2
- TODO:
3
- - add origin to Id
4
- """
5
1
  import itertools
6
2
  import typing as ta
7
3
 
8
4
  from ... import cached
9
- from ... import check
10
5
  from ... import dataclasses as dc
11
6
  from ... import lang
12
7
  from ..bindings import Binding
@@ -20,6 +15,7 @@ from ..providers import Provider
20
15
  from ..scopes import Singleton
21
16
  from .elements import ElementCollection
22
17
  from .injector import AsyncInjectorImpl
18
+ from .injector import create_async_injector
23
19
  from .providers import InternalProvider
24
20
  from .providers import ProviderImpl
25
21
 
@@ -48,7 +44,7 @@ class PrivateInjectorProviderImpl(ProviderImpl, lang.Final):
48
44
  return ()
49
45
 
50
46
  async def provide(self, injector: AsyncInjector) -> ta.Any:
51
- return check.isinstance(injector, AsyncInjectorImpl).create_child(self.ec)
47
+ return await create_async_injector(self.ec, injector)
52
48
 
53
49
 
54
50
  ##
@@ -1,7 +1,3 @@
1
- """
2
- TODO:
3
- - required_keys
4
- """
5
1
  import abc
6
2
  import typing as ta
7
3
 
@@ -1,9 +1,3 @@
1
- """
2
- TODO:
3
- - ContextVar ('context')
4
- - greenlet?
5
- - dynamic? https://github.com/wrmsr/iceworm/blob/2f6b4d5e9d237ef9665f7d57cfa6ce328efa0757/iceworm/utils/inject.py#L44
6
- """
7
1
  import abc
8
2
  import contextlib
9
3
  import threading
@@ -154,18 +148,20 @@ class SeededScopeImpl(ScopeImpl):
154
148
  self._ii = check.isinstance(i, _injector.AsyncInjectorImpl)
155
149
  self._ssi = check.isinstance(self._ii.get_scope_impl(self._ss), SeededScopeImpl)
156
150
 
157
- @contextlib.asynccontextmanager
158
- async def __call__(self, seeds: ta.Mapping[Key, ta.Any]) -> ta.AsyncGenerator[None]:
159
- try:
160
- if self._ssi._st is not None: # noqa
161
- raise ScopeAlreadyOpenError(self._ss)
162
- self._ssi._st = SeededScopeImpl.State(dict(seeds)) # noqa
163
- await self._ii._instantiate_eagers(self._ss) # noqa
164
- yield
165
- finally:
166
- if self._ssi._st is None: # noqa
167
- raise ScopeNotOpenError(self._ss)
168
- self._ssi._st = None # noqa
151
+ def __call__(self, seeds: ta.Mapping[Key, ta.Any]) -> ta.AsyncContextManager[None]:
152
+ @contextlib.asynccontextmanager
153
+ async def inner():
154
+ try:
155
+ if self._ssi._st is not None: # noqa
156
+ raise ScopeAlreadyOpenError(self._ss)
157
+ self._ssi._st = SeededScopeImpl.State(dict(seeds)) # noqa
158
+ await self._ii._instantiate_eagers(self._ss) # noqa
159
+ yield
160
+ finally:
161
+ if self._ssi._st is None: # noqa
162
+ raise ScopeNotOpenError(self._ss)
163
+ self._ssi._st = None # noqa
164
+ return inner()
169
165
 
170
166
  def auto_elements(self) -> Elements:
171
167
  return as_elements(
omlish/inject/inspect.py CHANGED
@@ -68,3 +68,12 @@ def tag(obj: T, **kwargs: ta.Any) -> T:
68
68
 
69
69
  def build_kwargs_target(obj: ta.Any, **kwargs: ta.Any) -> KwargsTarget:
70
70
  return _inspect.build_kwargs_target(obj, **kwargs)
71
+
72
+
73
+ ##
74
+
75
+
76
+ def target(**kwargs: ta.Any) -> ta.Callable[[ta.Any], KwargsTarget]:
77
+ def inner(obj: ta.Any) -> KwargsTarget:
78
+ return KwargsTarget.of(obj, **kwargs)
79
+ return inner
omlish/inject/multis.py CHANGED
@@ -1,8 +1,5 @@
1
1
  """
2
2
  TODO:
3
- - DynamicSetBinding / DynamicMapBinding ? provider of set[T] / map[K, V] ?
4
- - doable not guicey - too much dynamism
5
- - scopes
6
3
  """
7
4
  import collections.abc
8
5
  import typing as ta
omlish/inject/scopes.py CHANGED
@@ -89,14 +89,16 @@ def bind_scope_seed(k: ta.Any, ss: SeededScope) -> Element:
89
89
  ##
90
90
 
91
91
 
92
- @contextlib.asynccontextmanager
93
- async def async_enter_seeded_scope(
92
+ def async_enter_seeded_scope(
94
93
  i: '_injector.AsyncInjector',
95
94
  ss: SeededScope,
96
95
  keys: ta.Mapping[Key, ta.Any],
97
- ) -> ta.AsyncGenerator[None]:
98
- async with (await i.provide(Key(SeededScope.Manager, tag=ss)))(keys):
99
- yield
96
+ ) -> ta.AsyncContextManager[None]:
97
+ @contextlib.asynccontextmanager
98
+ async def inner():
99
+ async with (await i.provide(Key(SeededScope.Manager, tag=ss)))(keys):
100
+ yield
101
+ return inner()
100
102
 
101
103
 
102
104
  def enter_seeded_scope(
omlish/io/buffers.py CHANGED
@@ -190,16 +190,18 @@ class ReadableListBuffer:
190
190
  super().__init__()
191
191
 
192
192
  self._lst: list[bytes] = []
193
+ self._len = 0
193
194
 
194
195
  def __bool__(self) -> ta.NoReturn:
195
196
  raise TypeError("Use 'buf is not None' or 'len(buf)'.")
196
197
 
197
198
  def __len__(self) -> int:
198
- return sum(map(len, self._lst))
199
+ return self._len
199
200
 
200
201
  def feed(self, d: bytes) -> None:
201
202
  if d:
202
203
  self._lst.append(d)
204
+ self._len += len(d)
203
205
 
204
206
  def _chop(self, i: int, e: int) -> bytes:
205
207
  lst = self._lst
@@ -215,6 +217,8 @@ class ReadableListBuffer:
215
217
  *lst[i + 1:],
216
218
  ]
217
219
 
220
+ self._len -= len(o)
221
+
218
222
  return o
219
223
 
220
224
  def read(self, n: ta.Optional[int] = None) -> ta.Optional[bytes]:
@@ -224,6 +228,7 @@ class ReadableListBuffer:
224
228
 
225
229
  o = b''.join(self._lst)
226
230
  self._lst = []
231
+ self._len = 0
227
232
  return o
228
233
 
229
234
  if not (lst := self._lst):
@@ -293,7 +298,12 @@ class ReadableListBuffer:
293
298
  if not (b := self._raw.read1(n)):
294
299
  break
295
300
  self._buf.feed(b)
296
- return self._buf.read(n) or b''
301
+
302
+ if len(self._buf) >= n:
303
+ return self._buf.read(n) or b''
304
+
305
+ # EOF with a partial buffer: return what we have.
306
+ return self._buf.read() or b''
297
307
 
298
308
  def readall(self) -> bytes:
299
309
  buf = io.BytesIO()
@@ -343,7 +353,12 @@ class ReadableListBuffer:
343
353
  if not (b := await self._raw.read1(n)):
344
354
  break
345
355
  self._buf.feed(b)
346
- return self._buf.read(n) or b''
356
+
357
+ if len(self._buf) >= n:
358
+ return self._buf.read(n) or b''
359
+
360
+ # EOF with a partial buffer: return what we have.
361
+ return self._buf.read() or b''
347
362
 
348
363
  async def readall(self) -> bytes:
349
364
  buf = io.BytesIO()
@@ -396,16 +411,28 @@ class IncrementalWriteBuffer:
396
411
 
397
412
  t = 0
398
413
  for i, d in enumerate(lst): # noqa
399
- n = fn(check.not_empty(d))
414
+ d = check.not_empty(d)
415
+ n = fn(d)
400
416
  if not n:
401
417
  break
418
+
419
+ if n > len(d):
420
+ raise ValueError(n)
421
+
402
422
  t += n
403
423
 
424
+ if n < len(d):
425
+ # Short write - keep the remainder of this chunk and stop.
426
+ self._lst = [
427
+ d[n:],
428
+ *lst[i + 1:],
429
+ ]
430
+ self._pos += t
431
+ return t
432
+
404
433
  if t:
405
- self._lst = [
406
- *([d[n:]] if n < len(d) else []),
407
- *lst[i + 1:],
408
- ]
434
+ # Only fully-written chunks were consumed.
435
+ self._lst = lst[i + 1:]
409
436
  self._pos += t
410
437
 
411
438
  return t
omlish/lang/__init__.py CHANGED
@@ -341,6 +341,7 @@ with _auto_proxy_init(globals(), update_exports=True):
341
341
  ilen,
342
342
  take,
343
343
  consume,
344
+ opt_list,
344
345
  peek,
345
346
  chunk,
346
347
  interleave,
@@ -381,6 +382,8 @@ with _auto_proxy_init(globals(), update_exports=True):
381
382
  from .objects import ( # noqa
382
383
  arg_repr,
383
384
  opt_repr,
385
+ just_repr,
386
+ opt_or_just_repr,
384
387
 
385
388
  can_weakref,
386
389
 
@@ -466,6 +469,10 @@ with _auto_proxy_init(globals(), update_exports=True):
466
469
  iterslice,
467
470
  iterrange,
468
471
 
472
+ seqs_all,
473
+ seqs_equal,
474
+ seqs_identical,
475
+
469
476
  SeqView,
470
477
  )
471
478
 
@@ -622,6 +629,7 @@ with _auto_proxy_init(globals(), update_exports=True):
622
629
  Func3,
623
630
 
624
631
  CachedFunc0,
632
+ AsyncCachedFunc0,
625
633
 
626
634
  typing_annotations_attr,
627
635
  )
@@ -3,6 +3,7 @@ import functools
3
3
  import threading
4
4
  import typing as ta
5
5
 
6
+ from ...lite.abstract import Abstract
6
7
  from .restrict import Final
7
8
  from .restrict import NotInstantiable
8
9
 
@@ -40,7 +41,7 @@ class _MarkerMeta(abc.ABCMeta):
40
41
  else:
41
42
  if set(namespace) - _MARKER_NAMESPACE_KEYS:
42
43
  raise TypeError('Markers must not include contents. Did you mean to use Namespace?')
43
- if Final not in bases:
44
+ if Final not in bases and Abstract not in bases:
44
45
  bases += (Final,)
45
46
 
46
47
  return super().__new__(mcls, name, bases, namespace)
omlish/lang/iterables.py CHANGED
@@ -26,6 +26,12 @@ def consume(it: ta.Iterable[ta.Any]) -> None:
26
26
  collections.deque(it, maxlen=0)
27
27
 
28
28
 
29
+ def opt_list(it: ta.Iterable[T] | None) -> list[T] | None:
30
+ if it is None:
31
+ return None
32
+ return list(it)
33
+
34
+
29
35
  def peek(vs: ta.Iterable[T]) -> tuple[T, ta.Iterator[T]]:
30
36
  it = iter(vs)
31
37
  v = next(it)
omlish/lang/objects.py CHANGED
@@ -2,6 +2,7 @@ import types
2
2
  import typing as ta
3
3
  import weakref
4
4
 
5
+ from ..lite.maybes import Maybe
5
6
  from .classes.abstract import is_abstract_class
6
7
 
7
8
 
@@ -24,6 +25,18 @@ def opt_repr(obj: ta.Any) -> str | None:
24
25
  return repr(obj)
25
26
 
26
27
 
28
+ def just_repr(obj: Maybe) -> str | None:
29
+ return obj.map(repr).or_none()
30
+
31
+
32
+ def opt_or_just_repr(obj: ta.Any) -> str | None:
33
+ if isinstance(obj, Maybe):
34
+ if obj.present:
35
+ return repr(obj)
36
+ return None
37
+ return opt_repr(obj)
38
+
39
+
27
40
  ##
28
41
 
29
42
 
omlish/lang/outcomes.py CHANGED
@@ -214,7 +214,7 @@ class Value(Outcome[ValueT_co], ta.Generic[ValueT_co]):
214
214
 
215
215
  @property
216
216
  def is_error(self) -> bool:
217
- return True
217
+ return False
218
218
 
219
219
  def value(self) -> ValueT_co:
220
220
  return self._value
omlish/lang/recursion.py CHANGED
@@ -65,7 +65,7 @@ def recursion_limiting_context(key: ta.Any, limit: int | None) -> ta.Iterator[in
65
65
  except KeyError:
66
66
  pd = None
67
67
  else:
68
- if not isinstance(pd, int) and pd > 0: # type: ignore[operator]
68
+ if not (isinstance(pd, int) and pd > 0):
69
69
  raise RuntimeError
70
70
 
71
71
  if pd is not None and pd >= limit:
omlish/lang/sequences.py CHANGED
@@ -8,6 +8,7 @@ TODO:
8
8
  - shorter repr if __len__ > some threshold
9
9
  - use materialize()?
10
10
  """
11
+ import operator
11
12
  import typing as ta
12
13
 
13
14
 
@@ -36,6 +37,38 @@ def iterrange(
36
37
  ##
37
38
 
38
39
 
40
+ def seqs_all(
41
+ fn: ta.Callable[[T, T], bool],
42
+ l_seq: ta.Sequence[T],
43
+ *r_seqs: ta.Sequence[T],
44
+ ) -> bool:
45
+ if not all(len(r_seq) == len(l_seq) for r_seq in r_seqs):
46
+ return False
47
+
48
+ return all(
49
+ fn(l, r)
50
+ for r_seq in r_seqs
51
+ for l, r in zip(l_seq, r_seq, strict=True)
52
+ )
53
+
54
+
55
+ def seqs_equal(
56
+ l_seq: ta.Sequence[T],
57
+ *r_seqs: ta.Sequence[T],
58
+ ) -> bool:
59
+ return seqs_all(operator.eq, l_seq, *r_seqs)
60
+
61
+
62
+ def seqs_identical(
63
+ l_seq: ta.Sequence[T],
64
+ *r_seqs: ta.Sequence[T],
65
+ ) -> bool:
66
+ return seqs_all(operator.is_, l_seq, *r_seqs)
67
+
68
+
69
+ ##
70
+
71
+
39
72
  @ta.final
40
73
  class SeqView(ta.Sequence[T]):
41
74
  def __init__(self, data: ta.Sequence[T], slice_: slice = slice(None)) -> None:
@@ -94,7 +94,7 @@ def _process_dataclass__80a0a85b19250d1d39ff826c429bd05f9be201e1():
94
94
  def __setattr__(self, name, value):
95
95
  if (
96
96
  type(self) is __dataclass__cls
97
- or name in __dataclass___setattr_frozen_fields
97
+ or name in __dataclass___setattr_frozen_fields
98
98
  ):
99
99
  raise __dataclass__FrozenInstanceError(f"cannot assign to field {name!r}")
100
100
  super(__dataclass__cls, self).__setattr__(name, value)
@@ -111,7 +111,7 @@ def _process_dataclass__80a0a85b19250d1d39ff826c429bd05f9be201e1():
111
111
  def __delattr__(self, name):
112
112
  if (
113
113
  type(self) is __dataclass__cls
114
- or name in __dataclass___delattr_frozen_fields
114
+ or name in __dataclass___delattr_frozen_fields
115
115
  ):
116
116
  raise __dataclass__FrozenInstanceError(f"cannot delete field {name!r}")
117
117
  super(__dataclass__cls, self).__delattr__(name)
@@ -229,7 +229,7 @@ def _process_dataclass__32f5b8178dfdf24f4db24e8d8cd63ebd10bf83f3():
229
229
  def __setattr__(self, name, value):
230
230
  if (
231
231
  type(self) is __dataclass__cls
232
- or name in __dataclass___setattr_frozen_fields
232
+ or name in __dataclass___setattr_frozen_fields
233
233
  ):
234
234
  raise __dataclass__FrozenInstanceError(f"cannot assign to field {name!r}")
235
235
  super(__dataclass__cls, self).__setattr__(name, value)
@@ -246,7 +246,7 @@ def _process_dataclass__32f5b8178dfdf24f4db24e8d8cd63ebd10bf83f3():
246
246
  def __delattr__(self, name):
247
247
  if (
248
248
  type(self) is __dataclass__cls
249
- or name in __dataclass___delattr_frozen_fields
249
+ or name in __dataclass___delattr_frozen_fields
250
250
  ):
251
251
  raise __dataclass__FrozenInstanceError(f"cannot delete field {name!r}")
252
252
  super(__dataclass__cls, self).__delattr__(name)
@@ -408,7 +408,7 @@ def _process_dataclass__d177836dcedc950662bdf1c8a8d52e05fc91c5c7():
408
408
  def __setattr__(self, name, value):
409
409
  if (
410
410
  type(self) is __dataclass__cls
411
- or name in __dataclass___setattr_frozen_fields
411
+ or name in __dataclass___setattr_frozen_fields
412
412
  ):
413
413
  raise __dataclass__FrozenInstanceError(f"cannot assign to field {name!r}")
414
414
  super(__dataclass__cls, self).__setattr__(name, value)
@@ -429,7 +429,7 @@ def _process_dataclass__d177836dcedc950662bdf1c8a8d52e05fc91c5c7():
429
429
  def __delattr__(self, name):
430
430
  if (
431
431
  type(self) is __dataclass__cls
432
- or name in __dataclass___delattr_frozen_fields
432
+ or name in __dataclass___delattr_frozen_fields
433
433
  ):
434
434
  raise __dataclass__FrozenInstanceError(f"cannot delete field {name!r}")
435
435
  super(__dataclass__cls, self).__delattr__(name)
@@ -567,7 +567,7 @@ def _process_dataclass__440e63ab60e5c95ef453ad0e63ffc0977bb48371():
567
567
  def __setattr__(self, name, value):
568
568
  if (
569
569
  type(self) is __dataclass__cls
570
- or name in __dataclass___setattr_frozen_fields
570
+ or name in __dataclass___setattr_frozen_fields
571
571
  ):
572
572
  raise __dataclass__FrozenInstanceError(f"cannot assign to field {name!r}")
573
573
  super(__dataclass__cls, self).__setattr__(name, value)
@@ -586,7 +586,7 @@ def _process_dataclass__440e63ab60e5c95ef453ad0e63ffc0977bb48371():
586
586
  def __delattr__(self, name):
587
587
  if (
588
588
  type(self) is __dataclass__cls
589
- or name in __dataclass___delattr_frozen_fields
589
+ or name in __dataclass___delattr_frozen_fields
590
590
  ):
591
591
  raise __dataclass__FrozenInstanceError(f"cannot delete field {name!r}")
592
592
  super(__dataclass__cls, self).__delattr__(name)
@@ -704,7 +704,7 @@ def _process_dataclass__6c47afef6781ac6bd88758815660ccbfefe8540e():
704
704
  def __setattr__(self, name, value):
705
705
  if (
706
706
  type(self) is __dataclass__cls
707
- or name in __dataclass___setattr_frozen_fields
707
+ or name in __dataclass___setattr_frozen_fields
708
708
  ):
709
709
  raise __dataclass__FrozenInstanceError(f"cannot assign to field {name!r}")
710
710
  super(__dataclass__cls, self).__setattr__(name, value)
@@ -723,7 +723,7 @@ def _process_dataclass__6c47afef6781ac6bd88758815660ccbfefe8540e():
723
723
  def __delattr__(self, name):
724
724
  if (
725
725
  type(self) is __dataclass__cls
726
- or name in __dataclass___delattr_frozen_fields
726
+ or name in __dataclass___delattr_frozen_fields
727
727
  ):
728
728
  raise __dataclass__FrozenInstanceError(f"cannot delete field {name!r}")
729
729
  super(__dataclass__cls, self).__delattr__(name)
@@ -863,7 +863,7 @@ def _process_dataclass__ebef99260c9b05bfd28fc9433dcc32af80493f10():
863
863
  def __setattr__(self, name, value):
864
864
  if (
865
865
  type(self) is __dataclass__cls
866
- or name in __dataclass___setattr_frozen_fields
866
+ or name in __dataclass___setattr_frozen_fields
867
867
  ):
868
868
  raise __dataclass__FrozenInstanceError(f"cannot assign to field {name!r}")
869
869
  super(__dataclass__cls, self).__setattr__(name, value)
@@ -883,7 +883,7 @@ def _process_dataclass__ebef99260c9b05bfd28fc9433dcc32af80493f10():
883
883
  def __delattr__(self, name):
884
884
  if (
885
885
  type(self) is __dataclass__cls
886
- or name in __dataclass___delattr_frozen_fields
886
+ or name in __dataclass___delattr_frozen_fields
887
887
  ):
888
888
  raise __dataclass__FrozenInstanceError(f"cannot delete field {name!r}")
889
889
  super(__dataclass__cls, self).__delattr__(name)
@@ -1014,7 +1014,7 @@ def _process_dataclass__375fd7fd537e2cfb878109217fe4c57607b10510():
1014
1014
  def __setattr__(self, name, value):
1015
1015
  if (
1016
1016
  type(self) is __dataclass__cls
1017
- or name in __dataclass___setattr_frozen_fields
1017
+ or name in __dataclass___setattr_frozen_fields
1018
1018
  ):
1019
1019
  raise __dataclass__FrozenInstanceError(f"cannot assign to field {name!r}")
1020
1020
  super(__dataclass__cls, self).__setattr__(name, value)
@@ -1031,7 +1031,7 @@ def _process_dataclass__375fd7fd537e2cfb878109217fe4c57607b10510():
1031
1031
  def __delattr__(self, name):
1032
1032
  if (
1033
1033
  type(self) is __dataclass__cls
1034
- or name in __dataclass___delattr_frozen_fields
1034
+ or name in __dataclass___delattr_frozen_fields
1035
1035
  ):
1036
1036
  raise __dataclass__FrozenInstanceError(f"cannot delete field {name!r}")
1037
1037
  super(__dataclass__cls, self).__delattr__(name)
@@ -1163,7 +1163,7 @@ def _process_dataclass__b3f39a9348415b6ae3908bd546728de8b2b6d308():
1163
1163
  def __setattr__(self, name, value):
1164
1164
  if (
1165
1165
  type(self) is __dataclass__cls
1166
- or name in __dataclass___setattr_frozen_fields
1166
+ or name in __dataclass___setattr_frozen_fields
1167
1167
  ):
1168
1168
  raise __dataclass__FrozenInstanceError(f"cannot assign to field {name!r}")
1169
1169
  super(__dataclass__cls, self).__setattr__(name, value)
@@ -1182,7 +1182,7 @@ def _process_dataclass__b3f39a9348415b6ae3908bd546728de8b2b6d308():
1182
1182
  def __delattr__(self, name):
1183
1183
  if (
1184
1184
  type(self) is __dataclass__cls
1185
- or name in __dataclass___delattr_frozen_fields
1185
+ or name in __dataclass___delattr_frozen_fields
1186
1186
  ):
1187
1187
  raise __dataclass__FrozenInstanceError(f"cannot delete field {name!r}")
1188
1188
  super(__dataclass__cls, self).__delattr__(name)
@@ -1317,7 +1317,7 @@ def _process_dataclass__56c73a66344b180e8ef52aca8500185dd538bf10():
1317
1317
  def __setattr__(self, name, value):
1318
1318
  if (
1319
1319
  type(self) is __dataclass__cls
1320
- or name in __dataclass___setattr_frozen_fields
1320
+ or name in __dataclass___setattr_frozen_fields
1321
1321
  ):
1322
1322
  raise __dataclass__FrozenInstanceError(f"cannot assign to field {name!r}")
1323
1323
  super(__dataclass__cls, self).__setattr__(name, value)
@@ -1335,7 +1335,7 @@ def _process_dataclass__56c73a66344b180e8ef52aca8500185dd538bf10():
1335
1335
  def __delattr__(self, name):
1336
1336
  if (
1337
1337
  type(self) is __dataclass__cls
1338
- or name in __dataclass___delattr_frozen_fields
1338
+ or name in __dataclass___delattr_frozen_fields
1339
1339
  ):
1340
1340
  raise __dataclass__FrozenInstanceError(f"cannot delete field {name!r}")
1341
1341
  super(__dataclass__cls, self).__delattr__(name)
@@ -123,21 +123,21 @@ def bind_async_lifecycle_registrar() -> inj.Elements:
123
123
  ##
124
124
 
125
125
 
126
- def bind_managed_lifecycle_manager() -> inj.Elements:
126
+ def bind_managed_lifecycle_manager(*, eager: bool | int = False) -> inj.Elements:
127
127
  # FIXME: lock?
128
128
  def inner(es: contextlib.ExitStack) -> LifecycleManager:
129
129
  return es.enter_context(lifecycle_context_manage(LifecycleManager()))
130
130
 
131
131
  return inj.as_elements(
132
- inj.bind(inner, singleton=True, eager=True),
132
+ inj.bind(inner, singleton=True, eager=eager),
133
133
  )
134
134
 
135
135
 
136
- def bind_async_managed_lifecycle_manager() -> inj.Elements:
136
+ def bind_async_managed_lifecycle_manager(*, eager: bool | int = False) -> inj.Elements:
137
137
  # FIXME: lock?
138
138
  async def inner(aes: contextlib.AsyncExitStack) -> AsyncLifecycleManager:
139
139
  return await aes.enter_async_context(async_lifecycle_context_manage(AsyncLifecycleManager()))
140
140
 
141
141
  return inj.as_elements(
142
- inj.bind(inner, singleton=True, eager=True),
142
+ inj.bind(inner, singleton=True, eager=eager),
143
143
  )
omlish/lite/maybes.py CHANGED
@@ -100,6 +100,13 @@ class Maybe(ta.Generic[T]):
100
100
  else:
101
101
  return other
102
102
 
103
+ @ta.final
104
+ def or_none(self) -> ta.Optional[T]:
105
+ if self.present:
106
+ return self.must()
107
+ else:
108
+ return None
109
+
103
110
  @ta.final
104
111
  def or_else_get(self, supplier: ta.Callable[[], ta.Union[T, U]]) -> ta.Union[T, U]:
105
112
  if self.present: