omlish 0.0.0.dev420__py3-none-any.whl → 0.0.0.dev422__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 (99) hide show
  1. omlish/__about__.py +2 -2
  2. omlish/asyncs/bluelet/core.py +2 -2
  3. omlish/asyncs/bluelet/events.py +4 -3
  4. omlish/asyncs/bluelet/files.py +2 -2
  5. omlish/asyncs/bluelet/sockets.py +2 -2
  6. omlish/collections/frozen.py +1 -1
  7. omlish/collections/kv/base.py +1 -1
  8. omlish/collections/multimaps.py +1 -1
  9. omlish/collections/persistent/treapmap.py +2 -1
  10. omlish/concurrent/threadlets.py +2 -2
  11. omlish/configs/formats.py +5 -4
  12. omlish/configs/processing/flattening.py +2 -1
  13. omlish/configs/processing/rewriting.py +2 -2
  14. omlish/configs/shadow.py +3 -2
  15. omlish/daemons/spawning.py +2 -2
  16. omlish/daemons/targets.py +1 -1
  17. omlish/daemons/waiting.py +2 -1
  18. omlish/dataclasses/impl/generation/base.py +3 -2
  19. omlish/dataclasses/impl/generation/compilation.py +2 -1
  20. omlish/dataclasses/impl/generation/ops.py +2 -2
  21. omlish/dataclasses/impl/generation/processor.py +1 -1
  22. omlish/dataclasses/metaclass/meta.py +1 -0
  23. omlish/dataclasses/tools/static.py +5 -1
  24. omlish/formats/dotenv.py +3 -1
  25. omlish/formats/logfmt.py +111 -0
  26. omlish/formats/yaml.py +1 -1
  27. omlish/funcs/builders.py +2 -1
  28. omlish/funcs/match.py +1 -1
  29. omlish/funcs/pairs.py +41 -23
  30. omlish/funcs/pipes.py +3 -1
  31. omlish/http/asgi.py +2 -1
  32. omlish/http/coro/client/io.py +3 -2
  33. omlish/http/coro/server/server.py +2 -2
  34. omlish/http/handlers.py +2 -1
  35. omlish/http/jwt.py +1 -1
  36. omlish/http/parsing.py +2 -2
  37. omlish/io/compress/base.py +3 -2
  38. omlish/io/coro/readers.py +4 -3
  39. omlish/io/fdio/handlers.py +3 -2
  40. omlish/io/fdio/pollers.py +3 -1
  41. omlish/lang/__init__.py +20 -8
  42. omlish/lang/attrs.py +3 -1
  43. omlish/lang/casing.py +3 -1
  44. omlish/lang/classes/abstract.py +35 -96
  45. omlish/lang/classes/virtual.py +2 -2
  46. omlish/lang/contextmanagers.py +6 -4
  47. omlish/lang/generators.py +2 -2
  48. omlish/lang/iterables.py +6 -6
  49. omlish/lang/objects.py +0 -58
  50. omlish/lang/outcomes.py +3 -1
  51. omlish/lang/typing.py +5 -24
  52. omlish/lite/abstract.py +119 -0
  53. omlish/lite/contextmanagers.py +4 -1
  54. omlish/lite/inject.py +9 -9
  55. omlish/lite/marshal.py +230 -114
  56. omlish/lite/maybes.py +3 -1
  57. omlish/lite/maysync.py +4 -2
  58. omlish/lite/objects.py +81 -0
  59. omlish/lite/reflect.py +0 -15
  60. omlish/lite/timeouts.py +3 -1
  61. omlish/lite/wrappers.py +23 -0
  62. omlish/logs/abc.py +21 -5
  63. omlish/logs/all.py +14 -3
  64. omlish/logs/callers.py +23 -4
  65. omlish/logs/configs.py +13 -10
  66. omlish/logs/levels.py +7 -0
  67. omlish/logs/protocol.py +84 -42
  68. omlish/logs/typed/__init__.py +0 -0
  69. omlish/logs/typed/bindings.py +537 -0
  70. omlish/logs/typed/contexts.py +138 -0
  71. omlish/logs/typed/types.py +484 -0
  72. omlish/logs/typed/values.py +114 -0
  73. omlish/marshal/__init__.py +1 -0
  74. omlish/os/atomics.py +3 -2
  75. omlish/os/deathpacts/base.py +4 -2
  76. omlish/os/forkhooks.py +2 -2
  77. omlish/os/pidfiles/pinning.py +2 -1
  78. omlish/reflect/types.py +4 -3
  79. omlish/secrets/crypto.py +1 -1
  80. omlish/sockets/bind.py +2 -1
  81. omlish/sockets/handlers.py +3 -2
  82. omlish/sockets/server/handlers.py +2 -1
  83. omlish/sockets/server/server.py +4 -3
  84. omlish/sql/api/base.py +2 -2
  85. omlish/subprocesses/asyncs.py +2 -1
  86. omlish/subprocesses/base.py +2 -2
  87. omlish/subprocesses/maysync.py +1 -2
  88. omlish/subprocesses/run.py +2 -1
  89. omlish/subprocesses/sync.py +2 -1
  90. omlish/term/coloring.py +3 -1
  91. omlish/testing/pytest/plugins/asyncs/backends/base.py +3 -1
  92. omlish/testing/unittest/loading.py +2 -2
  93. omlish/text/asdl.py +4 -3
  94. {omlish-0.0.0.dev420.dist-info → omlish-0.0.0.dev422.dist-info}/METADATA +1 -1
  95. {omlish-0.0.0.dev420.dist-info → omlish-0.0.0.dev422.dist-info}/RECORD +99 -89
  96. {omlish-0.0.0.dev420.dist-info → omlish-0.0.0.dev422.dist-info}/WHEEL +0 -0
  97. {omlish-0.0.0.dev420.dist-info → omlish-0.0.0.dev422.dist-info}/entry_points.txt +0 -0
  98. {omlish-0.0.0.dev420.dist-info → omlish-0.0.0.dev422.dist-info}/licenses/LICENSE +0 -0
  99. {omlish-0.0.0.dev420.dist-info → omlish-0.0.0.dev422.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,537 @@
1
+ # ruff: noqa: UP006 UP007 UP045
2
+ # @omlish-lite
3
+ """
4
+ TODO:
5
+ - optimization of just using ChainMap when override?
6
+ - TypedLoggerBindings as Abstract, FullTLB and LimitedTLB subtypes, limited
7
+ - TypedLoggerBindingsBuilder ?
8
+ """
9
+ import abc
10
+ import collections
11
+ import functools
12
+ import itertools
13
+ import typing as ta
14
+
15
+ from ...lite.abstract import Abstract
16
+ from .types import TYPED_LOGGER_VALUE_OR_PROVIDER_OR_ABSENT_TYPES
17
+ from .types import TYPED_LOGGER_VALUE_OR_PROVIDER_TYPES
18
+ from .types import DefaultTypedLoggerValue
19
+ from .types import TypedLoggerConstFieldValue
20
+ from .types import TypedLoggerField
21
+ from .types import TypedLoggerFieldValue
22
+ from .types import TypedLoggerValue
23
+ from .types import TypedLoggerValueOrAbsent
24
+ from .types import TypedLoggerValueOrProvider # noqa
25
+ from .types import TypedLoggerValueOrProviderOrAbsent
26
+ from .types import TypedLoggerValueProvider
27
+
28
+
29
+ TypedLoggerBindingItem = ta.Union['TypedLoggerField', 'TypedLoggerValueOrProvider', 'TypedLoggerBindings', 'TypedLoggerValueWrapper'] # ta.TypeAlias # noqa
30
+
31
+ ChainTypedLoggerBindingItem = ta.Union['TypedLoggerField', 'TypedLoggerValueOrProvider'] # ta.TypeAlias
32
+
33
+ TypedLoggerValueWrapperFn = ta.Callable[[ta.Any], 'TypedLoggerValue'] # ta.TypeAlias
34
+
35
+
36
+ ##
37
+
38
+
39
+ class TypedLoggerDuplicateBindingsError(Exception):
40
+ def __init__(
41
+ self,
42
+ *,
43
+ keys: ta.Optional[ta.Dict[str, ta.List[TypedLoggerFieldValue]]] = None,
44
+ values: ta.Optional[ta.Dict[ta.Type[TypedLoggerValue], ta.List[TypedLoggerValueOrProviderOrAbsent]]] = None,
45
+ wrappers: ta.Optional[ta.Dict[type, ta.List[TypedLoggerValueWrapperFn]]] = None,
46
+ ) -> None:
47
+ super().__init__()
48
+
49
+ self.keys = keys
50
+ self.values = values
51
+ self.wrappers = wrappers
52
+
53
+ def __repr__(self) -> str:
54
+ return (
55
+ f'{self.__class__.__name__}(' +
56
+ ', '.join([
57
+ *([f'keys={self.keys!r}'] if self.keys is not None else []),
58
+ *([f'values={self.values!r}'] if self.values is not None else []),
59
+ *([f'wrappers={self.wrappers!r}'] if self.wrappers is not None else []),
60
+ ]) +
61
+ f')'
62
+ )
63
+
64
+
65
+ class TypedLoggerBindings(Abstract):
66
+ @property
67
+ @abc.abstractmethod
68
+ def key_map(self) -> ta.Mapping[str, TypedLoggerFieldValue]:
69
+ raise NotImplementedError
70
+
71
+ @abc.abstractmethod
72
+ def lookup_value(self, cls: ta.Type[TypedLoggerValue]) -> ta.Optional[TypedLoggerValueOrProviderOrAbsent]:
73
+ raise NotImplementedError
74
+
75
+ @property
76
+ @abc.abstractmethod
77
+ def const_value_map(self) -> ta.Mapping[ta.Type[TypedLoggerValue], TypedLoggerValueOrAbsent]:
78
+ raise NotImplementedError
79
+
80
+ @property
81
+ @abc.abstractmethod
82
+ def value_wrapper_fn(self) -> ta.Optional[TypedLoggerValueWrapperFn]:
83
+ raise NotImplementedError
84
+
85
+ #
86
+
87
+ @ta.final
88
+ class _Visitor(ta.NamedTuple):
89
+ accept_key: ta.Callable[[str, TypedLoggerFieldValue], None]
90
+ accept_keys: ta.Callable[[ta.Iterable[ta.Tuple[str, TypedLoggerFieldValue]]], None]
91
+
92
+ accept_value: ta.Callable[[ta.Type[TypedLoggerValue], TypedLoggerValueOrProviderOrAbsent], None]
93
+ accept_values: ta.Callable[[ta.Iterable[ta.Tuple[ta.Type[TypedLoggerValue], TypedLoggerValueOrProviderOrAbsent]]], None] # noqa
94
+
95
+ accept_const_values: ta.Callable[[ta.Iterable[ta.Tuple[ta.Type[TypedLoggerValue], TypedLoggerValueOrAbsent]]], None] # noqa
96
+
97
+ accept_value_wrapping: ta.Callable[[ta.Union['TypedLoggerValueWrapper', 'FullTypedLoggerBindings._ValueWrappingState']], None] # noqa
98
+
99
+ @abc.abstractmethod
100
+ def _typed_logger_visit_bindings(self, vst: _Visitor) -> None:
101
+ raise NotImplementedError
102
+
103
+
104
+ ##
105
+
106
+
107
+ @ta.final
108
+ class FullTypedLoggerBindings(TypedLoggerBindings):
109
+ def __init__(
110
+ self,
111
+ *items: TypedLoggerBindingItem,
112
+ override: bool = False,
113
+ ) -> None:
114
+ kd: ta.Dict[str, TypedLoggerFieldValue] = {}
115
+ dup_kd: ta.Dict[str, ta.List[TypedLoggerFieldValue]] = {}
116
+
117
+ vd: ta.Dict[ta.Type[TypedLoggerValue], TypedLoggerValueOrProviderOrAbsent] = {}
118
+ dup_vd: ta.Dict[ta.Type[TypedLoggerValue], ta.List[TypedLoggerValueOrProviderOrAbsent]] = {}
119
+
120
+ cvd: ta.Dict[ta.Type[TypedLoggerValue], TypedLoggerValueOrAbsent] = {}
121
+
122
+ vwl: ta.List[ta.Union[TypedLoggerValueWrapper, FullTypedLoggerBindings._ValueWrappingState]] = []
123
+
124
+ vst: TypedLoggerBindings._Visitor
125
+
126
+ if not override:
127
+ def add_kd(kd_k: str, kd_v: TypedLoggerFieldValue) -> None: # noqa
128
+ if kd_k in kd:
129
+ dup_kd.setdefault(kd_k, []).append(kd_v)
130
+ else:
131
+ kd[kd_k] = kd_v
132
+
133
+ def add_vd(vd_k: 'ta.Type[TypedLoggerValue]', vd_v: TypedLoggerValueOrProviderOrAbsent) -> None: # noqa
134
+ if vd_k in vd:
135
+ dup_vd.setdefault(vd_k, []).append(vd_v)
136
+ else:
137
+ vd[vd_k] = vd_v
138
+
139
+ def add_kds(it: 'ta.Iterable[ta.Tuple[str, TypedLoggerFieldValue]]') -> None: # noqa
140
+ collections.deque(itertools.starmap(add_kd, it), maxlen=0)
141
+
142
+ def add_vds(it: 'ta.Iterable[ta.Tuple[ta.Type[TypedLoggerValue], TypedLoggerValueOrProviderOrAbsent]]') -> None: # noqa
143
+ collections.deque(itertools.starmap(add_vd, it), maxlen=0)
144
+
145
+ vst = TypedLoggerBindings._Visitor( # noqa
146
+ add_kd,
147
+ add_kds,
148
+
149
+ add_vd,
150
+ add_vds,
151
+
152
+ cvd.update,
153
+
154
+ vwl.append,
155
+ )
156
+
157
+ else:
158
+ vst = TypedLoggerBindings._Visitor( # noqa
159
+ kd.__setitem__,
160
+ kd.update,
161
+
162
+ vd.__setitem__,
163
+ vd.update,
164
+
165
+ cvd.update,
166
+
167
+ vwl.append,
168
+ )
169
+
170
+ for o in items:
171
+ o._typed_logger_visit_bindings(vst) # noqa
172
+
173
+ #
174
+
175
+ dup_vwd: ta.Optional[ta.Dict[type, ta.List[TypedLoggerValueWrapperFn]]] = None
176
+
177
+ vws: ta.Optional[FullTypedLoggerBindings._ValueWrappingState] = None
178
+ vwf: ta.Optional[TypedLoggerValueWrapperFn] = None
179
+
180
+ if vwl:
181
+ if len(vwl) == 1 and isinstance((vwl0 := vwl[0]), FullTypedLoggerBindings._ValueWrappingState):
182
+ vws = vwl0
183
+
184
+ else:
185
+ vwd: ta.Dict[type, TypedLoggerValueWrapperFn] = {}
186
+
187
+ add_vwd: ta.Callable[[type, TypedLoggerValueWrapperFn], None]
188
+
189
+ if not override:
190
+ dup_vwd = {}
191
+
192
+ def add_vwd(vw_ty: type, vw_fn: TypedLoggerValueWrapperFn) -> None: # noqa
193
+ if vw_ty in vwd:
194
+ dup_vwd.setdefault(vw_ty, []).append(vw_fn)
195
+ else:
196
+ vwd[vw_ty] = vw_fn
197
+
198
+ else:
199
+ add_vwd = vwd.__setitem__
200
+
201
+ for vo in vwl:
202
+ vo._typed_logger_visit_value_wrappers(add_vwd) # noqa
203
+
204
+ if vwd and not dup_vwd:
205
+ vws = FullTypedLoggerBindings._ValueWrappingState(vwd)
206
+ vwf = vws.sdf
207
+
208
+ #
209
+
210
+ if dup_kd or dup_vd or dup_vwd:
211
+ raise TypedLoggerDuplicateBindingsError(
212
+ keys=dup_kd or None,
213
+ values=dup_vd or None,
214
+ wrappers=dup_vwd or None,
215
+ )
216
+
217
+ self._key_map: ta.Mapping[str, TypedLoggerFieldValue] = kd
218
+ self._value_map: ta.Mapping[ta.Type[TypedLoggerValue], TypedLoggerValueOrProviderOrAbsent] = vd
219
+
220
+ self._const_value_map: ta.Mapping[ta.Type[TypedLoggerValue], TypedLoggerValueOrAbsent] = cvd
221
+
222
+ self._value_wrapping = vws
223
+ self._value_wrapper_fn = vwf
224
+
225
+ #
226
+
227
+ @property
228
+ def key_map(self) -> ta.Mapping[str, TypedLoggerFieldValue]:
229
+ return self._key_map
230
+
231
+ def lookup_value(self, cls: ta.Type[TypedLoggerValue]) -> ta.Optional[TypedLoggerValueOrProviderOrAbsent]:
232
+ return self._value_map.get(cls)
233
+
234
+ @property
235
+ def const_value_map(self) -> ta.Mapping[ta.Type[TypedLoggerValue], TypedLoggerValueOrAbsent]:
236
+ return self._const_value_map
237
+
238
+ @property
239
+ def value_wrapper_fn(self) -> ta.Optional[TypedLoggerValueWrapperFn]:
240
+ return self._value_wrapper_fn
241
+
242
+ #
243
+
244
+ @ta.final
245
+ class _ValueWrappingState:
246
+ def __init__(self, dct: ta.Mapping[type, TypedLoggerValueWrapperFn]) -> None:
247
+ self.dct = dct
248
+
249
+ @functools.singledispatch
250
+ def wrap_value(o: ta.Any) -> TypedLoggerValue:
251
+ raise UnhandledTypedValueWrapperTypeError(o)
252
+
253
+ collections.deque(itertools.starmap(wrap_value.register, self.dct.items()), maxlen=0)
254
+
255
+ self.sdf = wrap_value
256
+
257
+ #
258
+
259
+ def _typed_logger_visit_value_wrappers(self, fn: ta.Callable[[type, TypedLoggerValueWrapperFn], None]) -> None: # noqa
260
+ collections.deque(itertools.starmap(fn, self.dct.items()), maxlen=0)
261
+
262
+ #
263
+
264
+ def _typed_logger_visit_bindings(self, vst: TypedLoggerBindings._Visitor) -> None:
265
+ vst.accept_keys(self._key_map.items())
266
+ vst.accept_values(self._value_map.items())
267
+
268
+ vst.accept_const_values(self._const_value_map.items())
269
+
270
+ if (vws := self._value_wrapping) is not None:
271
+ vst.accept_value_wrapping(vws)
272
+
273
+
274
+ ##
275
+
276
+
277
+ class ChainTypedLoggerBindingsUnhandledItemError(Exception):
278
+ pass
279
+
280
+
281
+ @ta.final
282
+ class ChainTypedLoggerBindings(TypedLoggerBindings):
283
+ def __init__(
284
+ self,
285
+ parent: TypedLoggerBindings,
286
+ *items: ChainTypedLoggerBindingItem,
287
+ ) -> None:
288
+ kd: ta.Dict[str, TypedLoggerFieldValue] = {}
289
+ dup_kd: ta.Dict[str, ta.List[TypedLoggerFieldValue]] = {}
290
+
291
+ vd: ta.Dict[ta.Type[TypedLoggerValue], TypedLoggerValueOrProviderOrAbsent] = {}
292
+ dup_vd: ta.Dict[ta.Type[TypedLoggerValue], ta.List[TypedLoggerValueOrProviderOrAbsent]] = {}
293
+
294
+ pcv = dict(parent.const_value_map)
295
+ cvd: ta.Dict[ta.Type[TypedLoggerValue], TypedLoggerValueOrAbsent] = {}
296
+
297
+ def add_kd(kd_k: str, kd_v: TypedLoggerFieldValue) -> None: # noqa
298
+ if kd_k in kd:
299
+ dup_kd.setdefault(kd_k, []).append(kd_v)
300
+ else:
301
+ kd[kd_k] = kd_v
302
+
303
+ def add_vd(vd_k: 'ta.Type[TypedLoggerValue]', vd_v: TypedLoggerValueOrProviderOrAbsent) -> None: # noqa
304
+ if vd_k in vd:
305
+ dup_vd.setdefault(vd_k, []).append(vd_v)
306
+ else:
307
+ vd[vd_k] = vd_v
308
+ pcv.pop(vd_k, None)
309
+
310
+ def add_kds(it: 'ta.Iterable[ta.Tuple[str, TypedLoggerFieldValue]]') -> None: # noqa
311
+ collections.deque(itertools.starmap(add_kd, it), maxlen=0)
312
+
313
+ def add_vds(it: 'ta.Iterable[ta.Tuple[ta.Type[TypedLoggerValue], TypedLoggerValueOrProviderOrAbsent]]') -> None: # noqa
314
+ collections.deque(itertools.starmap(add_vd, it), maxlen=0)
315
+
316
+ def bad_type(*args, **kwargs): # noqa
317
+ raise ChainTypedLoggerBindingsUnhandledItemError
318
+
319
+ vst = TypedLoggerBindings._Visitor( # noqa
320
+ add_kd,
321
+ add_kds,
322
+
323
+ add_vd,
324
+ add_vds,
325
+
326
+ cvd.update,
327
+
328
+ bad_type,
329
+ )
330
+
331
+ for o in items:
332
+ try:
333
+ o._typed_logger_visit_bindings(vst) # noqa
334
+ except ChainTypedLoggerBindingsUnhandledItemError:
335
+ raise ChainTypedLoggerBindingsUnhandledItemError(o) from None
336
+
337
+ #
338
+
339
+ if dup_kd or dup_vd:
340
+ raise TypedLoggerDuplicateBindingsError(
341
+ keys=dup_kd or None,
342
+ values=dup_vd or None,
343
+ )
344
+
345
+ self._parent = parent
346
+
347
+ self._key_map = {**parent.key_map, **kd}
348
+ self._self_value_map = vd
349
+ self._const_value_map = {**pcv, **cvd}
350
+
351
+ @property
352
+ def key_map(self) -> ta.Mapping[str, TypedLoggerFieldValue]:
353
+ return self._key_map
354
+
355
+ def lookup_value(self, cls: ta.Type[TypedLoggerValue]) -> ta.Optional[TypedLoggerValueOrProviderOrAbsent]:
356
+ try:
357
+ return self._self_value_map[cls]
358
+ except KeyError:
359
+ pass
360
+ return self._parent.lookup_value(cls)
361
+
362
+ @property
363
+ def const_value_map(self) -> ta.Mapping[ta.Type[TypedLoggerValue], TypedLoggerValueOrAbsent]:
364
+ return self._const_value_map
365
+
366
+ @property
367
+ def value_wrapper_fn(self) -> ta.Optional[TypedLoggerValueWrapperFn]:
368
+ return self._parent.value_wrapper_fn
369
+
370
+ #
371
+
372
+ def _typed_logger_visit_bindings(self, vst: 'TypedLoggerBindings._Visitor') -> None:
373
+ self._parent._typed_logger_visit_bindings(vst) # noqa
374
+
375
+
376
+ ##
377
+
378
+
379
+ class UnhandledTypedValueWrapperTypeError(TypeError):
380
+ pass
381
+
382
+
383
+ @ta.final
384
+ class TypedLoggerValueWrapper(ta.NamedTuple):
385
+ tys: ta.AbstractSet[type]
386
+ fn: TypedLoggerValueWrapperFn
387
+
388
+ #
389
+
390
+ def _typed_logger_visit_bindings(self, vst: TypedLoggerBindings._Visitor) -> None: # noqa
391
+ vst.accept_value_wrapping(self)
392
+
393
+ def _typed_logger_visit_value_wrappers(self, fn: ta.Callable[[type, TypedLoggerValueWrapperFn], None]) -> None: # noqa
394
+ for ty in self.tys:
395
+ fn(ty, self.fn)
396
+
397
+
398
+ ##
399
+
400
+
401
+ TYPED_LOGGER_BINDING_ITEM_TYPES: ta.Tuple[ta.Type[TypedLoggerBindingItem], ...] = (
402
+ TypedLoggerField,
403
+ *TYPED_LOGGER_VALUE_OR_PROVIDER_TYPES,
404
+ TypedLoggerBindings,
405
+ TypedLoggerValueWrapper,
406
+ )
407
+
408
+
409
+ ##
410
+
411
+
412
+ CanTypedLoggerBinding = ta.Union[ # ta.TypeAlias # omlish-amalg-typing-no-move
413
+ TypedLoggerBindingItem,
414
+ ta.Type[TypedLoggerValue],
415
+ ta.Tuple[
416
+ str,
417
+ ta.Union[
418
+ TypedLoggerFieldValue,
419
+ ta.Any,
420
+ ],
421
+ ],
422
+ None,
423
+ ]
424
+
425
+ CanChainTypedLoggerBinding = ta.Union[ # ta.TypeAlias # omlish-amalg-typing-no-move
426
+ ChainTypedLoggerBindingItem,
427
+ ta.Type[TypedLoggerValue],
428
+ ta.Tuple[
429
+ str,
430
+ ta.Union[
431
+ TypedLoggerFieldValue,
432
+ ta.Any,
433
+ ],
434
+ ],
435
+ None,
436
+ ]
437
+
438
+
439
+ _AS_TYPED_LOGGER_BINDINGS_DIRECT_TYPES: ta.Tuple[type, ...] = (
440
+ TypedLoggerField,
441
+ TypedLoggerBindings,
442
+ TypedLoggerValueWrapper,
443
+ )
444
+
445
+ _AS_TYPED_LOGGER_BINDINGS_FIELD_VALUE_DIRECT_TYPES: ta.Tuple[type, ...] = (
446
+ *TYPED_LOGGER_VALUE_OR_PROVIDER_OR_ABSENT_TYPES,
447
+ TypedLoggerConstFieldValue,
448
+ )
449
+
450
+
451
+ def as_typed_logger_bindings(
452
+ *objs: CanTypedLoggerBinding,
453
+
454
+ add_default_keys: bool = False,
455
+ default_key_filter: ta.Optional[ta.Callable[[str], bool]] = None,
456
+
457
+ add_default_values: bool = False,
458
+ default_value_filter: ta.Optional[ta.Callable[[ta.Type[DefaultTypedLoggerValue]], bool]] = None,
459
+
460
+ value_wrapper: ta.Optional[TypedLoggerValueWrapperFn] = None,
461
+ ) -> ta.Sequence[TypedLoggerBindingItem]:
462
+ """This functionality is combined to preserve final key ordering."""
463
+
464
+ lst: ta.List[TypedLoggerBindingItem] = []
465
+
466
+ for o in objs:
467
+ if o is None:
468
+ continue
469
+
470
+ elif isinstance(o, _AS_TYPED_LOGGER_BINDINGS_DIRECT_TYPES):
471
+ lst.append(o) # type: ignore[arg-type]
472
+
473
+ elif isinstance(o, TypedLoggerValue):
474
+ lst.append(o)
475
+
476
+ if add_default_keys:
477
+ if (dk := o.default_key()) is not None:
478
+ if default_key_filter is None or default_key_filter(dk):
479
+ lst.append(TypedLoggerField(dk, o))
480
+
481
+ elif isinstance(o, TypedLoggerValueProvider):
482
+ lst.append(o)
483
+
484
+ if add_default_keys:
485
+ if (dk := o.cls.default_key()) is not None:
486
+ if default_key_filter is None or default_key_filter(dk):
487
+ lst.append(TypedLoggerField(dk, o))
488
+
489
+ elif isinstance(o, type) and issubclass(o, TypedLoggerValue):
490
+ b = False
491
+
492
+ if add_default_values and issubclass(o, DefaultTypedLoggerValue):
493
+ if (dp := o.default_provider()) is not None:
494
+ if default_value_filter is None or default_value_filter(o):
495
+ lst.append(dp)
496
+ b = True
497
+
498
+ if add_default_keys:
499
+ if (dk := o.default_key()) is not None:
500
+ if default_key_filter is None or default_key_filter(dk):
501
+ lst.append(TypedLoggerField(dk, o))
502
+ b = True
503
+
504
+ if not b:
505
+ raise TypeError(f'{o} was added as neither a default key nor a default value')
506
+
507
+ elif isinstance(o, tuple):
508
+ k, v = o
509
+ if not isinstance(k, str):
510
+ raise TypeError(k)
511
+
512
+ if (
513
+ isinstance(v, _AS_TYPED_LOGGER_BINDINGS_FIELD_VALUE_DIRECT_TYPES) or
514
+ (isinstance(o, type) and issubclass(o, TypedLoggerValue)) # type: ignore[unreachable]
515
+ ):
516
+ lst.append(TypedLoggerField(k, v)) # type: ignore[arg-type]
517
+
518
+ else:
519
+ lst.append(TypedLoggerField(k, TypedLoggerConstFieldValue(v)))
520
+
521
+ elif value_wrapper is not None:
522
+ wv = value_wrapper(o)
523
+ if not isinstance(wv, TypedLoggerValue):
524
+ raise TypeError(wv)
525
+
526
+ lst.append(wv)
527
+
528
+ if add_default_keys:
529
+ if (dk := wv.default_key()) is not None:
530
+ if default_key_filter is None or default_key_filter(dk):
531
+ lst.append(TypedLoggerField(dk, wv))
532
+
533
+ else:
534
+ # ta.assert_never(o)
535
+ raise TypeError(o)
536
+
537
+ return lst
@@ -0,0 +1,138 @@
1
+ # ruff: noqa: UP006 UP007 UP045
2
+ # @omlish-lite
3
+ import typing as ta
4
+
5
+ from .types import ABSENT_TYPED_LOGGER_VALUE
6
+ from .types import AbsentTypedLoggerValue
7
+ from .types import ResolvedTypedLoggerFieldValue
8
+ from .types import TypedLoggerFieldValue
9
+ from .types import TypedLoggerValue
10
+ from .types import TypedLoggerValueOrAbsent
11
+ from .types import UnwrappedTypedLoggerFieldValue
12
+ from .types import unwrap_typed_logger_field_value
13
+
14
+
15
+ if ta.TYPE_CHECKING:
16
+ from .bindings import TypedLoggerBindings
17
+
18
+
19
+ TypedLoggerValueT = ta.TypeVar('TypedLoggerValueT', bound='TypedLoggerValue')
20
+
21
+
22
+ ##
23
+
24
+
25
+ class RecursiveTypedLoggerValueError(Exception):
26
+ def __init__(self, cls: ta.Type[TypedLoggerValue], rec: ta.Sequence[ta.Type[TypedLoggerValue]]) -> None:
27
+ super().__init__()
28
+
29
+ self.cls = cls
30
+ self.rec = rec
31
+
32
+ def __repr__(self) -> str:
33
+ return (
34
+ f'{self.__class__.__name__}('
35
+ f'cls={self.cls!r}, '
36
+ f'rec={self.rec!r}'
37
+ f')'
38
+ )
39
+
40
+
41
+ class UnboundTypedLoggerValueError(Exception):
42
+ def __init__(self, cls: ta.Type[TypedLoggerValue]) -> None:
43
+ super().__init__()
44
+
45
+ self.cls = cls
46
+
47
+ def __repr__(self) -> str:
48
+ return f'{self.__class__.__name__}(cls={self.cls!r})'
49
+
50
+
51
+ #
52
+
53
+
54
+ @ta.final
55
+ class TypedLoggerContext:
56
+ def __init__(
57
+ self,
58
+ bindings: 'TypedLoggerBindings',
59
+ *,
60
+ no_auto_default_values: bool = False,
61
+ default_absent: bool = False,
62
+ ) -> None:
63
+ super().__init__()
64
+
65
+ self._bindings = bindings
66
+ self._no_auto_default_values = no_auto_default_values
67
+ self._default_absent = default_absent
68
+
69
+ self._values: ta.Dict[ta.Type[TypedLoggerValue], TypedLoggerValueOrAbsent] = dict(bindings.const_value_map) # noqa
70
+ self._rec: ta.Dict[ta.Type[TypedLoggerValue], None] = {}
71
+
72
+ @property
73
+ def bindings(self) -> 'TypedLoggerBindings':
74
+ return self._bindings
75
+
76
+ @property
77
+ def no_auto_default_values(self) -> bool:
78
+ return self._no_auto_default_values
79
+
80
+ @property
81
+ def default_absent(self) -> bool:
82
+ return self._default_absent
83
+
84
+ #
85
+
86
+ def __getitem__(self, cls: ta.Type[TypedLoggerValueT]) -> ta.Union[TypedLoggerValueT, AbsentTypedLoggerValue]:
87
+ try:
88
+ return self._values[cls] # type: ignore[return-value]
89
+ except KeyError:
90
+ pass
91
+
92
+ if not issubclass(cls, TypedLoggerValue):
93
+ raise TypeError(cls)
94
+
95
+ if cls in self._rec:
96
+ raise RecursiveTypedLoggerValueError(cls, list(self._rec))
97
+
98
+ self._rec[cls] = None
99
+ try:
100
+ v: ta.Union[TypedLoggerValueOrAbsent]
101
+
102
+ if (bv := self._bindings.lookup_value(cls)) is not None:
103
+ if bv is ABSENT_TYPED_LOGGER_VALUE: # noqa
104
+ v = ABSENT_TYPED_LOGGER_VALUE
105
+
106
+ else:
107
+ v = bv._typed_logger_provide_value(self) # noqa
108
+
109
+ else:
110
+ if not self._no_auto_default_values and (dt := cls._typed_logger_maybe_provide_default_value(self)):
111
+ [v] = dt
112
+
113
+ elif self._default_absent:
114
+ v = ABSENT_TYPED_LOGGER_VALUE
115
+
116
+ else:
117
+ raise UnboundTypedLoggerValueError(cls) from None
118
+
119
+ self._values[cls] = v
120
+ return v # type: ignore[return-value]
121
+
122
+ finally:
123
+ self._rec.pop(cls)
124
+
125
+ #
126
+
127
+ def resolve_field_value(self, fv: TypedLoggerFieldValue) -> ResolvedTypedLoggerFieldValue:
128
+ if fv is ABSENT_TYPED_LOGGER_VALUE:
129
+ return fv # type: ignore[return-value]
130
+
131
+ elif isinstance(fv, type):
132
+ return self[fv]._typed_logger_resolve_field_value(self) # type: ignore[type-var] # noqa
133
+
134
+ else:
135
+ return fv._typed_logger_resolve_field_value(self) # noqa
136
+
137
+ def unwrap_field_value(self, fv: TypedLoggerFieldValue) -> UnwrappedTypedLoggerFieldValue:
138
+ return unwrap_typed_logger_field_value(self.resolve_field_value(fv))