omlish 0.0.0.dev484__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 (93) hide show
  1. omlish/CODESTYLE.md +345 -0
  2. omlish/README.md +199 -0
  3. omlish/__about__.py +12 -5
  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/impl/generation/plans.py +2 -17
  9. omlish/dataclasses/impl/generation/processor.py +2 -2
  10. omlish/dataclasses/impl/processing/driving.py +13 -1
  11. omlish/dataclasses/tools/replace.py +27 -0
  12. omlish/diag/_pycharm/runhack.py +1 -1
  13. omlish/dispatch/functions.py +1 -1
  14. omlish/formats/json/stream/lexing.py +13 -5
  15. omlish/formats/json/stream/parsing.py +1 -1
  16. omlish/inject/README.md +430 -0
  17. omlish/inject/__init__.py +20 -11
  18. omlish/inject/_dataclasses.py +1545 -1383
  19. omlish/inject/binder.py +7 -4
  20. omlish/inject/eagers.py +2 -4
  21. omlish/inject/elements.py +4 -0
  22. omlish/inject/helpers/late.py +76 -0
  23. omlish/inject/{managed.py → helpers/managed.py} +37 -34
  24. omlish/inject/impl/elements.py +7 -4
  25. omlish/inject/impl/injector.py +14 -26
  26. omlish/inject/impl/inspect.py +0 -8
  27. omlish/inject/impl/origins.py +1 -0
  28. omlish/inject/impl/privates.py +2 -6
  29. omlish/inject/impl/providers.py +0 -4
  30. omlish/inject/impl/scopes.py +14 -18
  31. omlish/inject/inspect.py +10 -1
  32. omlish/inject/multis.py +0 -3
  33. omlish/inject/scopes.py +7 -5
  34. omlish/io/buffers.py +35 -8
  35. omlish/lang/__init__.py +10 -0
  36. omlish/lang/classes/simple.py +2 -1
  37. omlish/lang/iterables.py +6 -0
  38. omlish/lang/objects.py +13 -0
  39. omlish/lang/outcomes.py +1 -1
  40. omlish/lang/recursion.py +1 -1
  41. omlish/lang/sequences.py +33 -0
  42. omlish/lifecycles/README.md +30 -0
  43. omlish/lifecycles/__init__.py +87 -13
  44. omlish/lifecycles/_dataclasses.py +1388 -0
  45. omlish/lifecycles/base.py +178 -64
  46. omlish/lifecycles/contextmanagers.py +113 -4
  47. omlish/lifecycles/controller.py +150 -87
  48. omlish/lifecycles/injection.py +143 -0
  49. omlish/lifecycles/listeners.py +56 -0
  50. omlish/lifecycles/managed.py +142 -0
  51. omlish/lifecycles/manager.py +218 -93
  52. omlish/lifecycles/states.py +2 -0
  53. omlish/lifecycles/transitions.py +3 -0
  54. omlish/lifecycles/unwrap.py +57 -0
  55. omlish/lite/maybes.py +7 -0
  56. omlish/lite/typing.py +33 -0
  57. omlish/logs/_amalg.py +1 -1
  58. omlish/logs/all.py +36 -11
  59. omlish/logs/asyncs.py +73 -0
  60. omlish/logs/base.py +101 -12
  61. omlish/logs/bisync.py +99 -0
  62. omlish/logs/contexts.py +4 -1
  63. omlish/logs/lists.py +125 -0
  64. omlish/logs/modules.py +19 -1
  65. omlish/logs/std/loggers.py +6 -1
  66. omlish/logs/std/noisy.py +11 -9
  67. omlish/logs/{standard.py → std/standard.py} +3 -4
  68. omlish/logs/utils.py +16 -1
  69. omlish/marshal/_dataclasses.py +813 -813
  70. omlish/reflect/__init__.py +43 -26
  71. omlish/reflect/ops.py +10 -1
  72. omlish/specs/jmespath/_dataclasses.py +597 -597
  73. omlish/specs/jsonschema/keywords/_dataclasses.py +244 -244
  74. omlish/sql/__init__.py +24 -5
  75. omlish/sql/api/dbapi.py +1 -1
  76. omlish/sql/dbapi/__init__.py +15 -0
  77. omlish/sql/{dbapi.py → dbapi/drivers.py} +2 -2
  78. omlish/sql/queries/__init__.py +3 -0
  79. omlish/testing/pytest/plugins/asyncs/plugin.py +2 -0
  80. omlish/text/docwrap/cli.py +5 -0
  81. omlish/typedvalues/_collection.cc +500 -0
  82. omlish/typedvalues/collection.py +159 -62
  83. omlish/typedvalues/generic.py +5 -4
  84. omlish/typedvalues/values.py +6 -0
  85. {omlish-0.0.0.dev484.dist-info → omlish-0.0.0.dev506.dist-info}/METADATA +14 -9
  86. {omlish-0.0.0.dev484.dist-info → omlish-0.0.0.dev506.dist-info}/RECORD +92 -77
  87. omlish/lifecycles/abstract.py +0 -86
  88. /omlish/inject/{impl → helpers}/proxy.py +0 -0
  89. /omlish/sql/{abc.py → dbapi/abc.py} +0 -0
  90. {omlish-0.0.0.dev484.dist-info → omlish-0.0.0.dev506.dist-info}/WHEEL +0 -0
  91. {omlish-0.0.0.dev484.dist-info → omlish-0.0.0.dev506.dist-info}/entry_points.txt +0 -0
  92. {omlish-0.0.0.dev484.dist-info → omlish-0.0.0.dev506.dist-info}/licenses/LICENSE +0 -0
  93. {omlish-0.0.0.dev484.dist-info → omlish-0.0.0.dev506.dist-info}/top_level.txt +0 -0
@@ -4,160 +4,285 @@ from .. import check
4
4
  from .. import collections as col
5
5
  from .. import dataclasses as dc
6
6
  from .. import lang
7
- from .abstract import AbstractLifecycle
7
+ from .base import AnyLifecycle
8
+ from .base import AsyncLifecycle
8
9
  from .base import Lifecycle
10
+ from .base import as_async_lifecycle
11
+ from .controller import AnyLifecycleController
12
+ from .controller import AsyncLifecycleController
9
13
  from .controller import LifecycleController
14
+ from .managed import AsyncLifecycleManaged
15
+ from .managed import LifecycleManaged
10
16
  from .states import LifecycleState
11
17
  from .states import LifecycleStateError
12
18
  from .states import LifecycleStates
13
19
 
14
20
 
21
+ LifecycleControllerT = ta.TypeVar('LifecycleControllerT', bound=AnyLifecycleController)
22
+
23
+
15
24
  ##
16
25
 
17
26
 
18
- class LifecycleManager(AbstractLifecycle):
19
- @dc.dataclass(frozen=True)
20
- class Entry(lang.Final):
21
- controller: LifecycleController
22
- dependencies: ta.MutableSet['LifecycleManager.Entry'] = dc.field(default_factory=col.IdentitySet)
23
- dependents: ta.MutableSet['LifecycleManager.Entry'] = dc.field(default_factory=col.IdentitySet)
27
+ @dc.dataclass(frozen=True, eq=False)
28
+ class LifecycleManagerEntry(lang.Final, ta.Generic[LifecycleControllerT]):
29
+ controller: LifecycleControllerT
30
+
31
+ dependencies: ta.MutableSet['LifecycleManagerEntry'] = dc.field(default_factory=set)
32
+ dependents: ta.MutableSet['LifecycleManagerEntry'] = dc.field(default_factory=set)
33
+
24
34
 
35
+ #
36
+
37
+
38
+ @ta.final
39
+ class _InnerLifecycleManager(AsyncLifecycleManaged, lang.Final):
25
40
  def __init__(
26
41
  self,
27
- *,
28
- lock: lang.DefaultLockable = None,
42
+ get_state: ta.Callable[[], LifecycleState],
29
43
  ) -> None:
30
44
  super().__init__()
31
45
 
32
- self._lock = lang.default_lock(lock, False)
33
-
34
- self._entries_by_lifecycle: ta.MutableMapping[Lifecycle, LifecycleManager.Entry] = col.IdentityKeyDict()
35
-
36
- self._controller = LifecycleController(self._lifecycle, lock=self._lock)
46
+ self._get_state = get_state
37
47
 
38
- @property
39
- def controller(self) -> LifecycleController:
40
- return self._controller
48
+ self._entries_by_lifecycle: ta.MutableMapping[AnyLifecycle, LifecycleManagerEntry] = col.IdentityKeyDict()
41
49
 
42
- @property
43
- def state(self) -> LifecycleState:
44
- return self._controller.state
50
+ #
45
51
 
46
- @staticmethod
47
- def _get_controller(lifecycle: Lifecycle) -> LifecycleController:
48
- if isinstance(lifecycle, LifecycleController):
52
+ def _get_or_make_controller(self, lifecycle: AnyLifecycle) -> AnyLifecycleController:
53
+ if isinstance(lifecycle, (LifecycleController, AsyncLifecycleController)):
49
54
  return lifecycle
50
- # elif isinstance(lifecycle, AbstractLifecycle):
51
- # return lifecycle.lifecycle_controller
55
+
52
56
  elif isinstance(lifecycle, Lifecycle):
53
57
  return LifecycleController(lifecycle)
58
+
59
+ elif isinstance(lifecycle, AsyncLifecycle):
60
+ return AsyncLifecycleController(lifecycle)
61
+
54
62
  else:
55
63
  raise TypeError(lifecycle)
56
64
 
57
- def _add_internal(self, lifecycle: Lifecycle, dependencies: ta.Iterable[Lifecycle]) -> Entry:
58
- check.state(self.state < LifecycleStates.STOPPING and not self.state.is_failed)
65
+ def _add_internal(self, lifecycle: AnyLifecycle, dependencies: ta.Iterable[AnyLifecycle]) -> LifecycleManagerEntry:
66
+ check.state(self._get_state() < LifecycleStates.STOPPING and not self._get_state().is_failed)
59
67
 
60
- check.isinstance(lifecycle, Lifecycle)
68
+ check.isinstance(lifecycle, (Lifecycle, AsyncLifecycle))
61
69
  try:
62
70
  entry = self._entries_by_lifecycle[lifecycle]
63
71
  except KeyError:
64
- controller = self._get_controller(lifecycle)
65
- entry = self._entries_by_lifecycle[lifecycle] = LifecycleManager.Entry(controller)
72
+ controller = self._get_or_make_controller(lifecycle)
73
+ entry = self._entries_by_lifecycle[lifecycle] = LifecycleManagerEntry(controller)
66
74
 
67
75
  for dep in dependencies:
68
- check.isinstance(dep, Lifecycle)
76
+ check.isinstance(dep, (Lifecycle, AsyncLifecycle))
69
77
  dep_entry = self._add_internal(dep, [])
70
78
  entry.dependencies.add(dep_entry)
71
79
  dep_entry.dependents.add(entry)
72
80
 
73
81
  return entry
74
82
 
75
- def add(
83
+ async def add(
76
84
  self,
77
- lifecycle: Lifecycle,
78
- dependencies: ta.Iterable[Lifecycle] = (),
79
- ) -> Entry:
80
- check.state(self.state < LifecycleStates.STOPPING and not self.state.is_failed)
81
-
82
- with self._lock():
83
- entry = self._add_internal(lifecycle, dependencies)
84
-
85
- if self.state >= LifecycleStates.CONSTRUCTING:
86
- def rec(e):
87
- if e.controller.state < LifecycleStates.CONSTRUCTED:
88
- for dep in e.dependencies:
89
- rec(dep)
90
- e.controller.lifecycle_construct()
91
- rec(entry)
92
-
93
- if self.state >= LifecycleStates.STARTING:
94
- def rec(e):
95
- if e.controller.state < LifecycleStates.STARTED:
96
- for dep in e.dependencies:
97
- rec(dep)
98
- e.controller.lifecycle_start()
99
- rec(entry)
100
-
101
- return entry
85
+ lifecycle: AnyLifecycle,
86
+ dependencies: ta.Iterable[AnyLifecycle] = (),
87
+ ) -> LifecycleManagerEntry:
88
+ check.state(self._get_state() < LifecycleStates.STOPPING and not self._get_state().is_failed)
89
+
90
+ entry = self._add_internal(lifecycle, dependencies)
91
+
92
+ if self._get_state() >= LifecycleStates.CONSTRUCTING:
93
+ async def rec(e):
94
+ if e.controller.state < LifecycleStates.CONSTRUCTED:
95
+ for dep in e.dependencies:
96
+ await rec(dep)
97
+
98
+ await as_async_lifecycle(e.controller).lifecycle_construct()
99
+
100
+ await rec(entry)
101
+
102
+ if self._get_state() >= LifecycleStates.STARTING:
103
+ async def rec(e):
104
+ if e.controller.state < LifecycleStates.STARTED:
105
+ for dep in e.dependencies:
106
+ await rec(dep)
107
+
108
+ await as_async_lifecycle(e.controller).lifecycle_start()
109
+
110
+ await rec(entry)
111
+
112
+ return entry
102
113
 
103
114
  ##
104
115
 
105
116
  @ta.override
106
- def _lifecycle_construct(self) -> None:
107
- def rec(entry: LifecycleManager.Entry) -> None:
108
- for dep in entry.dependencies:
109
- rec(dep)
117
+ async def _lifecycle_construct(self) -> None:
118
+ async def rec(e: LifecycleManagerEntry) -> None:
119
+ for dep in e.dependencies:
120
+ await rec(dep)
110
121
 
111
- if entry.controller.state.is_failed:
112
- raise LifecycleStateError(entry.controller)
122
+ if e.controller.state.is_failed:
123
+ raise LifecycleStateError(e.controller)
113
124
 
114
- if entry.controller.state < LifecycleStates.CONSTRUCTED:
115
- entry.controller.lifecycle_construct()
125
+ if e.controller.state < LifecycleStates.CONSTRUCTED:
126
+ await as_async_lifecycle(e.controller).lifecycle_construct()
116
127
 
117
128
  for entry in self._entries_by_lifecycle.values():
118
- rec(entry)
129
+ await rec(entry)
119
130
 
120
131
  @ta.override
121
- def _lifecycle_start(self) -> None:
122
- def rec(entry: LifecycleManager.Entry) -> None:
123
- for dep in entry.dependencies:
124
- rec(dep)
132
+ async def _lifecycle_start(self) -> None:
133
+ async def rec(e: LifecycleManagerEntry) -> None:
134
+ for dep in e.dependencies:
135
+ await rec(dep)
125
136
 
126
- if entry.controller.state.is_failed:
127
- raise LifecycleStateError(entry.controller)
137
+ if e.controller.state.is_failed:
138
+ raise LifecycleStateError(e.controller)
128
139
 
129
- if entry.controller.state < LifecycleStates.CONSTRUCTED:
130
- entry.controller.lifecycle_construct()
140
+ if e.controller.state < LifecycleStates.CONSTRUCTED:
141
+ await as_async_lifecycle(e.controller).lifecycle_construct()
131
142
 
132
- if entry.controller.state < LifecycleStates.STARTED:
133
- entry.controller.lifecycle_start()
143
+ if e.controller.state < LifecycleStates.STARTED:
144
+ await as_async_lifecycle(e.controller).lifecycle_start()
134
145
 
135
146
  for entry in self._entries_by_lifecycle.values():
136
- rec(entry)
147
+ await rec(entry)
137
148
 
138
149
  @ta.override
139
- def _lifecycle_stop(self) -> None:
140
- def rec(entry: LifecycleManager.Entry) -> None:
141
- for dep in entry.dependents:
142
- rec(dep)
150
+ async def _lifecycle_stop(self) -> None:
151
+ async def rec(e: LifecycleManagerEntry) -> None:
152
+ for dep in e.dependents:
153
+ await rec(dep)
143
154
 
144
- if entry.controller.state.is_failed:
145
- raise LifecycleStateError(entry.controller)
155
+ if e.controller.state.is_failed:
156
+ raise LifecycleStateError(e.controller)
146
157
 
147
- if entry.controller.state is LifecycleStates.STARTED:
148
- entry.controller.lifecycle_stop()
158
+ if e.controller.state is LifecycleStates.STARTED:
159
+ await as_async_lifecycle(e.controller).lifecycle_stop()
149
160
 
150
161
  for entry in self._entries_by_lifecycle.values():
151
- rec(entry)
162
+ await rec(entry)
152
163
 
153
164
  @ta.override
154
- def _lifecycle_destroy(self) -> None:
155
- def rec(entry: LifecycleManager.Entry) -> None:
156
- for dep in entry.dependents:
157
- rec(dep)
165
+ async def _lifecycle_destroy(self) -> None:
166
+ async def rec(e: LifecycleManagerEntry) -> None:
167
+ for dep in e.dependents:
168
+ await rec(dep)
158
169
 
159
- if entry.controller.state < LifecycleStates.DESTROYED:
160
- entry.controller.lifecycle_destroy()
170
+ if e.controller.state < LifecycleStates.DESTROYED:
171
+ await as_async_lifecycle(e.controller).lifecycle_destroy()
161
172
 
162
173
  for entry in self._entries_by_lifecycle.values():
163
- rec(entry)
174
+ await rec(entry)
175
+
176
+
177
+ ##
178
+
179
+
180
+ class LifecycleManager(LifecycleManaged, lang.Final):
181
+ def __init__(
182
+ self,
183
+ *,
184
+ lock: lang.DefaultLockable = None,
185
+ ) -> None:
186
+ super().__init__()
187
+
188
+ self._lock = lang.default_lock(lock, None)
189
+
190
+ self._inner = _InnerLifecycleManager(lambda: self._inner_controller.state)
191
+
192
+ self._inner_controller = AsyncLifecycleController(
193
+ self._inner._lifecycle, # noqa
194
+ lock=lambda: lang.SyncToAsyncContextManager(self._lock()),
195
+ )
196
+
197
+ #
198
+
199
+ @property
200
+ def state(self) -> LifecycleState:
201
+ return self._inner_controller.state
202
+
203
+ #
204
+
205
+ def add(
206
+ self,
207
+ lifecycle: Lifecycle,
208
+ dependencies: ta.Iterable[Lifecycle] = (),
209
+ ) -> LifecycleManagerEntry[LifecycleController]:
210
+ return lang.sync_await(self._inner.add(
211
+ check.isinstance(lifecycle, Lifecycle),
212
+ [check.isinstance(d, Lifecycle) for d in dependencies],
213
+ ))
214
+
215
+ #
216
+
217
+ @ta.override
218
+ def _lifecycle_construct(self) -> None:
219
+ return lang.sync_await(self._inner_controller.lifecycle_construct())
220
+
221
+ @ta.override
222
+ def _lifecycle_start(self) -> None:
223
+ return lang.sync_await(self._inner_controller.lifecycle_start())
224
+
225
+ @ta.override
226
+ def _lifecycle_stop(self) -> None:
227
+ return lang.sync_await(self._inner_controller.lifecycle_stop())
228
+
229
+ @ta.override
230
+ def _lifecycle_destroy(self) -> None:
231
+ return lang.sync_await(self._inner_controller.lifecycle_destroy())
232
+
233
+
234
+ #
235
+
236
+
237
+ class AsyncLifecycleManager(AsyncLifecycleManaged, lang.Final):
238
+ def __init__(
239
+ self,
240
+ *,
241
+ lock: lang.DefaultAsyncLockable = None,
242
+ ) -> None:
243
+ super().__init__()
244
+
245
+ self._lock = lang.default_async_lock(lock, None)
246
+
247
+ self._inner = _InnerLifecycleManager(lambda: self._inner_controller.state)
248
+
249
+ self._inner_controller = AsyncLifecycleController(
250
+ self._inner._lifecycle, # noqa
251
+ lock=self._lock,
252
+ )
253
+
254
+ #
255
+
256
+ @property
257
+ def state(self) -> LifecycleState:
258
+ return self._inner_controller.state
259
+
260
+ #
261
+
262
+ async def add(
263
+ self,
264
+ lifecycle: AnyLifecycle,
265
+ dependencies: ta.Iterable[AnyLifecycle] = (),
266
+ ) -> LifecycleManagerEntry[AnyLifecycleController]:
267
+ return await self._inner.add(
268
+ lifecycle,
269
+ dependencies,
270
+ )
271
+
272
+ #
273
+
274
+ @ta.override
275
+ async def _lifecycle_construct(self) -> None:
276
+ return await self._inner_controller.lifecycle_construct()
277
+
278
+ @ta.override
279
+ async def _lifecycle_start(self) -> None:
280
+ return await self._inner_controller.lifecycle_start()
281
+
282
+ @ta.override
283
+ async def _lifecycle_stop(self) -> None:
284
+ return await self._inner_controller.lifecycle_stop()
285
+
286
+ @ta.override
287
+ async def _lifecycle_destroy(self) -> None:
288
+ return await self._inner_controller.lifecycle_destroy()
@@ -1,4 +1,5 @@
1
1
  import functools
2
+ import typing as ta
2
3
 
3
4
  from .. import check
4
5
  from .. import dataclasses as dc
@@ -12,6 +13,7 @@ class LifecycleStateError(Exception):
12
13
  pass
13
14
 
14
15
 
16
+ @ta.final
15
17
  @dc.dataclass(frozen=True, eq=False)
16
18
  @functools.total_ordering
17
19
  class LifecycleState(lang.Final):
@@ -1,3 +1,5 @@
1
+ import typing as ta
2
+
1
3
  from .. import check
2
4
  from .. import dataclasses as dc
3
5
  from .. import lang
@@ -8,6 +10,7 @@ from .states import LifecycleStates
8
10
  ##
9
11
 
10
12
 
13
+ @ta.final
11
14
  @dc.dataclass(frozen=True)
12
15
  class LifecycleTransition(lang.Final):
13
16
  old: frozenset[LifecycleState]
@@ -0,0 +1,57 @@
1
+ import functools
2
+ import typing as ta
3
+
4
+ from .base import AsyncLifecycle
5
+ from .base import Lifecycle
6
+ from .managed import AsyncLifecycleManaged
7
+ from .managed import LifecycleManaged
8
+
9
+
10
+ ##
11
+
12
+
13
+ @functools.singledispatch
14
+ def unwrap_lifecycle(obj: ta.Any) -> Lifecycle | None:
15
+ return None
16
+
17
+
18
+ @unwrap_lifecycle.register
19
+ def _(obj: Lifecycle) -> Lifecycle:
20
+ return obj
21
+
22
+
23
+ @unwrap_lifecycle.register
24
+ def _(obj: LifecycleManaged) -> Lifecycle:
25
+ return obj._lifecycle # noqa
26
+
27
+
28
+ #
29
+
30
+
31
+ @functools.singledispatch
32
+ def unwrap_async_lifecycle(obj: ta.Any) -> AsyncLifecycle | None:
33
+ return None
34
+
35
+
36
+ @unwrap_async_lifecycle.register
37
+ def _(obj: AsyncLifecycle) -> AsyncLifecycle:
38
+ return obj
39
+
40
+
41
+ @unwrap_async_lifecycle.register
42
+ def _(obj: AsyncLifecycleManaged) -> AsyncLifecycle:
43
+ return obj._lifecycle # noqa
44
+
45
+
46
+ #
47
+
48
+
49
+ def unwrap_any_lifecycle(obj: ta.Any) -> Lifecycle | AsyncLifecycle | None:
50
+ if (lc := unwrap_lifecycle(obj)) is not None:
51
+ return lc
52
+
53
+ elif (alc := unwrap_async_lifecycle(obj)) is not None:
54
+ return alc
55
+
56
+ else:
57
+ return None
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:
omlish/lite/typing.py CHANGED
@@ -63,6 +63,39 @@ class Func3(ta.Generic[A0, A1, A2, T]):
63
63
  ##
64
64
 
65
65
 
66
+ @dc.dataclass(frozen=True)
67
+ class CachedFunc0(ta.Generic[T]):
68
+ fn: ta.Callable[[], T]
69
+
70
+ def __call__(self) -> T:
71
+ try:
72
+ return object.__getattribute__(self, '_value')
73
+ except AttributeError:
74
+ pass
75
+
76
+ value = self.fn()
77
+ object.__setattr__(self, '_value', value)
78
+ return value
79
+
80
+
81
+ @dc.dataclass(frozen=True)
82
+ class AsyncCachedFunc0(ta.Generic[T]):
83
+ fn: ta.Callable[[], ta.Awaitable[T]]
84
+
85
+ async def __call__(self) -> T:
86
+ try:
87
+ return object.__getattribute__(self, '_value')
88
+ except AttributeError:
89
+ pass
90
+
91
+ value = await self.fn()
92
+ object.__setattr__(self, '_value', value)
93
+ return value
94
+
95
+
96
+ ##
97
+
98
+
66
99
  _TYPING_ANNOTATIONS_ATTR = '__annotate__' if sys.version_info >= (3, 14) else '__annotations__'
67
100
 
68
101
 
omlish/logs/_amalg.py CHANGED
@@ -1,8 +1,8 @@
1
1
  # @omlish-lite
2
2
  # @omlish-amalg ../../omdev/scripts/lib/logs.py
3
3
  from .base import AnyLogger # noqa
4
- from .standard import configure_standard_logging # noqa
5
4
  from .std.loggers import StdLogger # noqa
5
+ from .std.standard import configure_standard_logging # noqa
6
6
 
7
7
 
8
8
  ##
omlish/logs/all.py CHANGED
@@ -38,7 +38,23 @@ with _lang.auto_proxy_init(globals()):
38
38
  LoggingContextLogRecord,
39
39
  )
40
40
 
41
+ from .std.standard import ( # noqa
42
+ STANDARD_LOG_FORMAT_PARTS,
43
+ StandardLoggingFormatter,
44
+
45
+ StandardConfiguredLoggingHandler,
46
+
47
+ configure_standard_logging,
48
+ )
49
+
50
+ from .asyncs import ( # noqa
51
+ AsyncLoggerToLogger,
52
+ LoggerToAsyncLogger,
53
+ )
54
+
41
55
  from .base import ( # noqa
56
+ LoggingMsgFn,
57
+
42
58
  AnyLogger,
43
59
  Logger,
44
60
  AsyncLogger,
@@ -48,8 +64,17 @@ with _lang.auto_proxy_init(globals()):
48
64
  AsyncNopLogger,
49
65
  )
50
66
 
67
+ from .bisync import ( # noqa
68
+ BisyncLogger,
69
+ BisyncAsyncLogger,
70
+ make_bisync_logger,
71
+ )
72
+
51
73
  from .contexts import ( # noqa
52
74
  LoggingContext,
75
+ SimpleLoggingContext,
76
+
77
+ CaptureLoggingContext,
53
78
  )
54
79
 
55
80
  from .formatters import ( # noqa
@@ -67,28 +92,28 @@ with _lang.auto_proxy_init(globals()):
67
92
  NamedLogLevel,
68
93
  )
69
94
 
95
+ from .lists import ( # noqa
96
+ AnyListLogger,
97
+ ListLogger,
98
+ AsyncLogger,
99
+ )
100
+
70
101
  from .modules import ( # noqa
71
102
  get_module_logger,
103
+ get_module_async_logger,
104
+ get_module_loggers,
72
105
  )
73
106
 
74
107
  from .protocols import ( # noqa
75
108
  LoggerLike,
76
109
  )
77
110
 
78
- from .standard import ( # noqa
79
- STANDARD_LOG_FORMAT_PARTS,
80
- StandardLoggingFormatter,
81
-
82
- StandardConfiguredLoggingHandler,
83
-
84
- configure_standard_logging,
85
- )
86
-
87
111
  from .utils import ( # noqa
112
+ exception_logging,
113
+ async_exception_logging,
114
+
88
115
  LogTimingContext,
89
116
  log_timing_context,
90
-
91
- exception_logging,
92
117
  )
93
118
 
94
119
  from .warnings import ( # noqa
omlish/logs/asyncs.py ADDED
@@ -0,0 +1,73 @@
1
+ # ruff: noqa: UP006 UP007 UP045 UP046
2
+ # @omlish-lite
3
+ import typing as ta
4
+
5
+ from ..lite.asyncs import sync_await
6
+ from ..lite.check import check
7
+ from .base import AsyncLogger
8
+ from .base import CaptureLoggingContext
9
+ from .base import Logger
10
+ from .base import LoggingMsgFn
11
+ from .contexts import CaptureLoggingContextImpl
12
+ from .infos import LoggingContextInfos
13
+ from .levels import LogLevel
14
+
15
+
16
+ ##
17
+
18
+
19
+ class AsyncLoggerToLogger(Logger):
20
+ def __init__(self, u: AsyncLogger) -> None:
21
+ super().__init__()
22
+
23
+ self._u = u
24
+
25
+ def get_effective_level(self) -> LogLevel:
26
+ return self._u.get_effective_level()
27
+
28
+ def _log(
29
+ self,
30
+ ctx: CaptureLoggingContext,
31
+ msg: ta.Union[str, tuple, LoggingMsgFn],
32
+ *args: ta.Any,
33
+ **kwargs: ta.Any,
34
+ ) -> None:
35
+ # Nope out early to avoid sync_await if possible - don't bother in the LoggerToAsyncLogger.
36
+ if not self.is_enabled_for(ctx.must_get_info(LoggingContextInfos.Level).level):
37
+ return
38
+
39
+ # Note: we hardcode the stack offset of sync_await (which is 2 - sync_await + sync_await.thunk). In non-lite
40
+ # code, lang.sync_await uses a cext if present to avoid being on the py stack, which would obviously complicate
41
+ # this, but this is lite code so we will always have the non-c version.
42
+ sync_await(
43
+ self._u._log( # noqa
44
+ check.isinstance(ctx, CaptureLoggingContextImpl).inc_stack_offset(3),
45
+ msg,
46
+ *args,
47
+ **kwargs,
48
+ ),
49
+ )
50
+
51
+
52
+ class LoggerToAsyncLogger(AsyncLogger):
53
+ def __init__(self, u: Logger) -> None:
54
+ super().__init__()
55
+
56
+ self._u = u
57
+
58
+ def get_effective_level(self) -> LogLevel:
59
+ return self._u.get_effective_level()
60
+
61
+ async def _log(
62
+ self,
63
+ ctx: CaptureLoggingContext,
64
+ msg: ta.Union[str, tuple, LoggingMsgFn],
65
+ *args: ta.Any,
66
+ **kwargs: ta.Any,
67
+ ) -> None:
68
+ return self._u._log( # noqa
69
+ check.isinstance(ctx, CaptureLoggingContextImpl).inc_stack_offset(),
70
+ msg,
71
+ *args,
72
+ **kwargs,
73
+ )