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,484 @@
1
+ # ruff: noqa: UP006 UP007 UP045 UP046
2
+ # @omlish-lite
3
+ import abc
4
+ import typing as ta
5
+
6
+ from ...lite.abstract import Abstract
7
+ from ...lite.reflect import is_union_alias
8
+ from ...lite.strings import snake_case
9
+ from ...lite.wrappers import update_wrapper_no_annotations
10
+
11
+
12
+ if ta.TYPE_CHECKING:
13
+ from .bindings import TypedLoggerBindings
14
+ from .contexts import TypedLoggerContext
15
+
16
+
17
+ T = ta.TypeVar('T')
18
+ U = ta.TypeVar('U')
19
+
20
+ TypedLoggerValueT = ta.TypeVar('TypedLoggerValueT', bound='TypedLoggerValue')
21
+
22
+ TypedLoggerValueOrProvider = ta.Union['TypedLoggerValue', 'TypedLoggerValueProvider'] # ta.TypeAlias
23
+
24
+ AbsentTypedLoggerValue = ta.Type['ABSENT_TYPED_LOGGER_VALUE'] # ta.TypeAlias
25
+
26
+ TypedLoggerValueOrAbsent = ta.Union['TypedLoggerValue', AbsentTypedLoggerValue]
27
+ TypedLoggerValueOrProviderOrAbsent = ta.Union[TypedLoggerValueOrProvider, AbsentTypedLoggerValue] # ta.TypeAlias
28
+
29
+ TypedLoggerFieldValue = ta.Union[TypedLoggerValueOrProviderOrAbsent, ta.Type['TypedLoggerValue'], 'TypedLoggerConstFieldValue'] # ta.TypeAlias # noqa
30
+ ResolvedTypedLoggerFieldValue = ta.Union[TypedLoggerValueOrAbsent, 'TypedLoggerConstFieldValue'] # ta.TypeAlias
31
+ UnwrappedTypedLoggerFieldValue = ta.Union[TypedLoggerValueOrAbsent, ta.Any] # ta.TypeAlias
32
+
33
+
34
+ ##
35
+
36
+
37
+ class _TypedLoggerInternalMethods(ta.Protocol): # noqa
38
+ def _typed_logger_provide_value(self, ctx: 'TypedLoggerContext') -> TypedLoggerValueOrAbsent: ... # noqa
39
+
40
+ def _typed_logger_maybe_provide_default_value(self, ctx: 'TypedLoggerContext') -> ta.Tuple[TypedLoggerValueOrAbsent, ...]: ... # noqa
41
+
42
+ def _typed_logger_resolve_field_value(self, ctx: 'TypedLoggerContext') -> ResolvedTypedLoggerFieldValue: ... # noqa
43
+
44
+ def _typed_logger_unwrap_field_value(self, ctx: 'TypedLoggerContext') -> UnwrappedTypedLoggerFieldValue: ... # noqa
45
+
46
+ def _typed_logger_visit_bindings(self, vst: 'TypedLoggerBindings._Visitor') -> None: ... # noqa
47
+
48
+
49
+ ##
50
+
51
+
52
+ @ta.final
53
+ class ABSENT_TYPED_LOGGER_VALUE: # noqa
54
+ def __new__(cls, *args, **kwargs): # noqa
55
+ raise TypeError
56
+
57
+ #
58
+
59
+ @classmethod
60
+ def map_absent(cls, fn: ta.Callable[[TypedLoggerValueT], U]) -> AbsentTypedLoggerValue: # noqa
61
+ return cls
62
+
63
+ #
64
+
65
+ @classmethod
66
+ def _typed_logger_provide_value(cls, ctx: 'TypedLoggerContext') -> TypedLoggerValueOrAbsent: # noqa
67
+ return cls
68
+
69
+ @classmethod
70
+ def _typed_logger_resolve_field_value(cls, ctx: 'TypedLoggerContext') -> ResolvedTypedLoggerFieldValue: # noqa
71
+ return cls
72
+
73
+ @classmethod
74
+ def _typed_logger_unwrap_field_value(cls, ctx: 'TypedLoggerContext') -> UnwrappedTypedLoggerFieldValue: # noqa
75
+ return cls
76
+
77
+
78
+ ##
79
+
80
+
81
+ class TypedLoggerValue(Abstract, ta.Generic[T]):
82
+ def __init__(self, v: T) -> None:
83
+ self._v = v
84
+
85
+ @classmethod
86
+ def of(cls: ta.Type[TypedLoggerValueT], v: ta.Any) -> ta.Union[TypedLoggerValueT, AbsentTypedLoggerValue]:
87
+ return cls(v) if v is not ABSENT_TYPED_LOGGER_VALUE else ABSENT_TYPED_LOGGER_VALUE
88
+
89
+ @property
90
+ def v(self) -> T:
91
+ return self._v
92
+
93
+ def __repr__(self) -> str:
94
+ return f'{self.__class__.__module__}.{self.__class__.__qualname__}({self._v!r})'
95
+
96
+ #
97
+
98
+ def map_absent( # noqa
99
+ self: TypedLoggerValueT,
100
+ fn: ta.Callable[[TypedLoggerValueT], U],
101
+ ) -> ta.Union[U, AbsentTypedLoggerValue]:
102
+ return fn(self)
103
+
104
+ #
105
+
106
+ _hash: int
107
+
108
+ def __hash__(self) -> int:
109
+ try:
110
+ return self._hash
111
+ except AttributeError:
112
+ pass
113
+ h = self._hash = hash((self.__class__, self.v))
114
+ return h
115
+
116
+ def __eq__(self, o):
117
+ if not isinstance(o, TypedLoggerValue):
118
+ return NotImplemented
119
+ return self.__class__ is o.__class__ and self.v == o.v
120
+
121
+ def __ne__(self, o):
122
+ return not (self == o)
123
+
124
+ #
125
+
126
+ _default_key: ta.ClassVar[ta.Union[str, bool]] = False
127
+
128
+ @ta.final
129
+ @classmethod
130
+ def default_key(cls) -> ta.Optional[str]:
131
+ return cls.__default_key # type: ignore[attr-defined]
132
+
133
+ #
134
+
135
+ class ContextLambda(ta.NamedTuple):
136
+ fn: ta.Callable[['TypedLoggerContext'], ta.Any]
137
+
138
+ #
139
+
140
+ def __init_subclass__(cls, **kwargs: ta.Any) -> None:
141
+ super().__init_subclass__(**kwargs)
142
+
143
+ if '__call__' in cls.__dict__:
144
+ raise TypeError(f'{cls} should not be callable')
145
+
146
+ try:
147
+ dtb = DefaultTypedLoggerValue
148
+ except NameError:
149
+ pass
150
+ else:
151
+ if hasattr(cls, '_default_value') and not issubclass(cls, dtb):
152
+ raise TypeError(f'{cls} should be a subclass of DefaultTypedLoggerValue if it has a _default_value')
153
+
154
+ dks: ta.Optional[str]
155
+ if isinstance((dk := getattr(cls, '_default_key')), str):
156
+ dks = dk
157
+ elif dk is True:
158
+ dks = snake_case(cls.__name__)
159
+ elif dk is False:
160
+ dks = None
161
+ else:
162
+ raise TypeError(dk)
163
+ cls.__default_key = dks # type: ignore[attr-defined]
164
+
165
+ #
166
+
167
+ @ta.final
168
+ def _typed_logger_provide_value(self, ctx: 'TypedLoggerContext') -> TypedLoggerValueOrAbsent: # noqa
169
+ return self
170
+
171
+ @classmethod
172
+ def _typed_logger_maybe_provide_default_value(cls, ctx: 'TypedLoggerContext') -> ta.Tuple[TypedLoggerValueOrAbsent, ...]: # noqa
173
+ return ()
174
+
175
+ @ta.final
176
+ def _typed_logger_resolve_field_value(self, ctx: 'TypedLoggerContext') -> ResolvedTypedLoggerFieldValue: # noqa
177
+ return self
178
+
179
+ @ta.final
180
+ def _typed_logger_unwrap_field_value(self, ctx: 'TypedLoggerContext') -> UnwrappedTypedLoggerFieldValue: # noqa
181
+ return self._v
182
+
183
+ @ta.final
184
+ def _typed_logger_visit_bindings(self, vst: 'TypedLoggerBindings._Visitor') -> None: # noqa
185
+ vst.accept_values(((type(self), self),))
186
+ vst.accept_const_values(((type(self), self),))
187
+
188
+
189
+ class DefaultTypedLoggerValue(TypedLoggerValue[T], Abstract):
190
+ _default_value: ta.ClassVar[ta.Union[
191
+ AbsentTypedLoggerValue,
192
+ classmethod,
193
+ TypedLoggerValue.ContextLambda,
194
+ ta.Any,
195
+ ]] = ABSENT_TYPED_LOGGER_VALUE
196
+
197
+ @ta.final
198
+ @classmethod
199
+ def default_provider(cls) -> 'TypedLoggerValueProvider':
200
+ try:
201
+ return cls.__default_provider # type: ignore[attr-defined]
202
+ except AttributeError:
203
+ pass
204
+
205
+ # Must be done late to support typing forwardrefs.
206
+ dp: TypedLoggerValueProvider
207
+ dv = next(mc.__dict__['_default_value'] for mc in cls.__mro__ if '_default_value' in mc.__dict__)
208
+
209
+ if dv is ABSENT_TYPED_LOGGER_VALUE:
210
+ dp = ConstTypedLoggerValueProvider(cls, ABSENT_TYPED_LOGGER_VALUE)
211
+
212
+ elif isinstance(dv, classmethod):
213
+ fn = dv.__get__(None, cls)
214
+ fl: ta.Any = lambda **kw: cls(v) if (v := fn(**kw)) is not ABSENT_TYPED_LOGGER_VALUE else v
215
+ dp = FnTypedLoggerValueProvider(cls, update_wrapper_no_annotations(fl, fn))
216
+
217
+ elif isinstance(dv, TypedLoggerValue.ContextLambda):
218
+ fl = lambda ctx: cls(dv.fn(ctx))
219
+ dp = ContextFnTypedLoggerValueProvider(cls, update_wrapper_no_annotations(fl, dv.fn))
220
+
221
+ else:
222
+ dp = ConstTypedLoggerValueProvider(cls, cls(dv))
223
+
224
+ cls.__default_provider = dp # type: ignore[attr-defined]
225
+ return dp
226
+
227
+ #
228
+
229
+ @ta.final
230
+ @classmethod
231
+ def _typed_logger_maybe_provide_default_value(cls, ctx: 'TypedLoggerContext') -> ta.Tuple[TypedLoggerValueOrAbsent, ...]: # noqa
232
+ return (cls.default_provider().provide_value(ctx),)
233
+
234
+
235
+ ##
236
+
237
+
238
+ class TypedLoggerValueProvider(Abstract, ta.Generic[TypedLoggerValueT]):
239
+ @property
240
+ @abc.abstractmethod
241
+ def cls(self) -> ta.Type[TypedLoggerValueT]:
242
+ raise NotImplementedError
243
+
244
+ @abc.abstractmethod
245
+ def provide_value(self, ctx: 'TypedLoggerContext') -> ta.Union[TypedLoggerValueT, AbsentTypedLoggerValue]:
246
+ raise NotImplementedError
247
+
248
+ #
249
+
250
+ @ta.final
251
+ def _typed_logger_provide_value(self, ctx: 'TypedLoggerContext') -> TypedLoggerValueOrAbsent: # noqa
252
+ return self.provide_value(ctx)
253
+
254
+ @ta.final
255
+ def _typed_logger_resolve_field_value(self, ctx: 'TypedLoggerContext') -> ResolvedTypedLoggerFieldValue: # noqa
256
+ return self.provide_value(ctx)
257
+
258
+ def _typed_logger_visit_bindings(self, vst: 'TypedLoggerBindings._Visitor') -> None: # noqa
259
+ vst.accept_values(((self.cls, self),))
260
+
261
+
262
+ #
263
+
264
+
265
+ class ConstTypedLoggerValueProvider(TypedLoggerValueProvider[TypedLoggerValueT]):
266
+ def __init__(
267
+ self,
268
+ cls: ta.Type[TypedLoggerValueT],
269
+ v: ta.Union[TypedLoggerValueT, AbsentTypedLoggerValue],
270
+ ) -> None:
271
+ super().__init__()
272
+
273
+ self._cls = cls
274
+ self._v = v
275
+
276
+ @property
277
+ def cls(self) -> ta.Type[TypedLoggerValueT]:
278
+ return self._cls
279
+
280
+ @property
281
+ def v(self) -> ta.Union[TypedLoggerValueT, AbsentTypedLoggerValue]:
282
+ return self._v
283
+
284
+ def provide_value(self, ctx: 'TypedLoggerContext') -> ta.Union[TypedLoggerValueT, AbsentTypedLoggerValue]:
285
+ return self._v
286
+
287
+ #
288
+
289
+ @ta.final
290
+ def _typed_logger_visit_bindings(self, vst: 'TypedLoggerBindings._Visitor') -> None: # noqa
291
+ vst.accept_values(((self.cls, self),))
292
+ vst.accept_const_values(((self.cls, self._v),))
293
+
294
+
295
+ #
296
+
297
+
298
+ @ta.final
299
+ class ContextFnTypedLoggerValueProvider(TypedLoggerValueProvider[TypedLoggerValueT]):
300
+ def __init__(
301
+ self,
302
+ cls: ta.Type[TypedLoggerValueT],
303
+ fn: ta.Callable[['TypedLoggerContext'], ta.Union[TypedLoggerValueT, AbsentTypedLoggerValue]],
304
+ ) -> None:
305
+ super().__init__()
306
+
307
+ self._cls = cls
308
+ self._fn = fn
309
+
310
+ @property
311
+ def cls(self) -> ta.Type[TypedLoggerValueT]:
312
+ return self._cls
313
+
314
+ @property
315
+ def fn(self) -> ta.Callable[['TypedLoggerContext'], ta.Union[TypedLoggerValueT, AbsentTypedLoggerValue]]:
316
+ return self._fn
317
+
318
+ def __repr__(self) -> str:
319
+ return f'{self.__class__.__name__}({self._cls!r}, {self._fn!r})'
320
+
321
+ def provide_value(self, ctx: 'TypedLoggerContext') -> ta.Union[TypedLoggerValueT, AbsentTypedLoggerValue]:
322
+ return self._fn(ctx)
323
+
324
+
325
+ #
326
+
327
+
328
+ class FnTypedLoggerValueProviderAnnotationError(TypeError):
329
+ pass
330
+
331
+
332
+ @ta.final
333
+ class FnTypedLoggerValueProvider(TypedLoggerValueProvider[TypedLoggerValueT]):
334
+ def __init__(
335
+ self,
336
+ cls: ta.Type[TypedLoggerValueT],
337
+ fn: ta.Callable[[], ta.Union[TypedLoggerValueT, AbsentTypedLoggerValue]],
338
+ ) -> None:
339
+ super().__init__()
340
+
341
+ self._cls = cls
342
+ self._fn = fn
343
+
344
+ self._kw = self._get_fn_kwargs(fn)
345
+
346
+ @classmethod
347
+ def _get_fn_kwargs(cls, fn: ta.Any) -> ta.Mapping[str, ta.Type[TypedLoggerValue]]:
348
+ o = fn
349
+ s = {o}
350
+ while hasattr(o, '__wrapped__'):
351
+ o = o.__wrapped__
352
+ if o in s:
353
+ raise RuntimeError(f'Recursive unwrap: {o!r} in {s!r}')
354
+ s.add(o)
355
+
356
+ def get_kw(anns: ta.Dict[str, ta.Any]) -> ta.Dict[str, ta.Type[TypedLoggerValue]]:
357
+ anns = dict(anns)
358
+ anns.pop('return', None)
359
+ if not anns:
360
+ return {}
361
+
362
+ kw: ta.Dict[str, ta.Type[TypedLoggerValue]] = {}
363
+ for k, v in anns.items():
364
+ def bad() -> ta.NoReturn:
365
+ raise FnTypedLoggerValueProviderAnnotationError(
366
+ f'{fn} has invalid annotation {k} of {v} - must be subtype of TypedLoggerValue or' # noqa
367
+ f'Union[TypedLoggerValue, AbsentTypedLoggerValue]',
368
+ )
369
+
370
+ a = v
371
+ if is_union_alias(a):
372
+ if len(us := set(a)) != 2 or AbsentTypedLoggerValue not in us:
373
+ bad()
374
+ [a] = us - {AbsentTypedLoggerValue}
375
+
376
+ if not (isinstance(a, type) and issubclass(a, TypedLoggerValue)):
377
+ bad()
378
+
379
+ kw[k] = a
380
+
381
+ return kw
382
+
383
+ try:
384
+ # Note: transparently falls back to magic property on 3.14+
385
+ return get_kw(getattr(o, '__annotations__', {}))
386
+ except FnTypedLoggerValueProviderAnnotationError:
387
+ pass
388
+
389
+ # This is much slower, so only do it if necessary.
390
+ return get_kw(ta.get_type_hints(o))
391
+
392
+ @property
393
+ def cls(self) -> ta.Type[TypedLoggerValueT]:
394
+ return self._cls
395
+
396
+ @property
397
+ def fn(self) -> ta.Callable[[], ta.Union[TypedLoggerValueT, AbsentTypedLoggerValue]]:
398
+ return self._fn
399
+
400
+ def __repr__(self) -> str:
401
+ return f'{self.__class__.__name__}({self._cls!r}, {self._fn!r})'
402
+
403
+ def provide_value(self, ctx: 'TypedLoggerContext') -> ta.Union[TypedLoggerValueT, AbsentTypedLoggerValue]:
404
+ return self._fn(**{
405
+ k: v
406
+ for k, c in self._kw.items()
407
+ if (v := ctx[c]) is not ABSENT_TYPED_LOGGER_VALUE
408
+ })
409
+
410
+
411
+ ##
412
+
413
+
414
+ @ta.final
415
+ class TypedLoggerConstFieldValue(ta.NamedTuple):
416
+ v: ta.Any
417
+
418
+ #
419
+
420
+ @ta.final
421
+ def _typed_logger_resolve_field_value(self, ctx: 'TypedLoggerContext') -> ResolvedTypedLoggerFieldValue: # noqa
422
+ return self
423
+
424
+ @ta.final
425
+ def _typed_logger_unwrap_field_value(self, ctx: 'TypedLoggerContext') -> UnwrappedTypedLoggerFieldValue: # noqa
426
+ return self.v
427
+
428
+
429
+ @ta.final
430
+ class TypedLoggerField(ta.NamedTuple):
431
+ k: str
432
+ v: TypedLoggerFieldValue
433
+
434
+ #
435
+
436
+ def _typed_logger_visit_bindings(self, vst: 'TypedLoggerBindings._Visitor') -> None: # noqa
437
+ vst.accept_keys(((self.k, self.v),))
438
+
439
+
440
+ ##
441
+
442
+
443
+ TYPED_LOGGER_VALUE_OR_PROVIDER_TYPES: ta.Tuple[ta.Type[TypedLoggerValueOrProvider], ...] = (
444
+ TypedLoggerValue,
445
+ TypedLoggerValueProvider,
446
+ )
447
+
448
+ TYPED_LOGGER_VALUE_OR_ABSENT_TYPES: ta.Tuple[ta.Union[
449
+ ta.Type[TypedLoggerValue],
450
+ AbsentTypedLoggerValue,
451
+ ], ...] = (
452
+ TypedLoggerValue,
453
+ ABSENT_TYPED_LOGGER_VALUE,
454
+ )
455
+
456
+ TYPED_LOGGER_VALUE_OR_PROVIDER_OR_ABSENT_TYPES: ta.Tuple[ta.Union[
457
+ ta.Type[TypedLoggerValueOrProvider],
458
+ AbsentTypedLoggerValue,
459
+ ], ...] = (
460
+ *TYPED_LOGGER_VALUE_OR_PROVIDER_TYPES,
461
+ ABSENT_TYPED_LOGGER_VALUE,
462
+ )
463
+
464
+
465
+ ##
466
+
467
+
468
+ @ta.overload
469
+ def unwrap_typed_logger_field_value(rfv: TypedLoggerValue[T]) -> TypedLoggerValue[T]:
470
+ ...
471
+
472
+
473
+ @ta.overload
474
+ def unwrap_typed_logger_field_value(rfv: AbsentTypedLoggerValue) -> AbsentTypedLoggerValue:
475
+ ...
476
+
477
+
478
+ @ta.overload
479
+ def unwrap_typed_logger_field_value(rfv: TypedLoggerConstFieldValue) -> ta.Any:
480
+ ...
481
+
482
+
483
+ def unwrap_typed_logger_field_value(rfv):
484
+ return rfv._typed_logger_unwrap_field_value(rfv) # noqa
@@ -0,0 +1,114 @@
1
+ # ruff: noqa: UP007
2
+ # @omlish-lite
3
+ import logging
4
+ import os
5
+ import sys
6
+ import threading
7
+ import time
8
+ import typing as ta
9
+
10
+ from ...logs.callers import LoggingCaller
11
+ from ...logs.levels import LogLevel
12
+ from .types import ABSENT_TYPED_LOGGER_VALUE
13
+ from .types import AbsentTypedLoggerValue
14
+ from .types import DefaultTypedLoggerValue
15
+ from .types import TypedLoggerValue
16
+
17
+
18
+ ##
19
+
20
+
21
+ class StandardTypedLoggerValues:
22
+ def __new__(cls, *args, **kwargs): # noqa
23
+ raise TypeError
24
+
25
+ #
26
+
27
+ class TimeNs(DefaultTypedLoggerValue[int]):
28
+ @classmethod
29
+ def _default_value(cls) -> float:
30
+ return time.time()
31
+
32
+ class Time(DefaultTypedLoggerValue[float]):
33
+ _default_key = True
34
+ _default_value = TypedLoggerValue.ContextLambda(
35
+ lambda ctx: ctx[StandardTypedLoggerValues.TimeNs].map_absent(
36
+ lambda tv: tv.v / 1e9,
37
+ ),
38
+ )
39
+
40
+ #
41
+
42
+ class Level(TypedLoggerValue[LogLevel]):
43
+ pass
44
+
45
+ class LevelName(DefaultTypedLoggerValue[str]):
46
+ _default_key = 'level'
47
+ _default_value = TypedLoggerValue.ContextLambda(
48
+ lambda ctx: ctx[StandardTypedLoggerValues.Level].map_absent(
49
+ lambda lvl: logging.getLevelName(lvl.v),
50
+ ),
51
+ )
52
+
53
+ #
54
+
55
+ class Msg(TypedLoggerValue[str]):
56
+ _default_key = True
57
+
58
+ #
59
+
60
+ class Caller(TypedLoggerValue[LoggingCaller]):
61
+ pass
62
+
63
+ #
64
+
65
+ class Tid(DefaultTypedLoggerValue[int]):
66
+ @classmethod
67
+ def _default_value(cls) -> ta.Union[int, AbsentTypedLoggerValue]:
68
+ if hasattr(threading, 'get_native_id'):
69
+ return threading.get_native_id()
70
+ else:
71
+ return ABSENT_TYPED_LOGGER_VALUE
72
+
73
+ class ThreadIdent(DefaultTypedLoggerValue[int]):
74
+ @classmethod
75
+ def _default_value(cls) -> int:
76
+ return threading.get_ident()
77
+
78
+ class ThreadName(DefaultTypedLoggerValue[int]):
79
+ @classmethod
80
+ def _default_value(cls) -> str:
81
+ return threading.current_thread().name
82
+
83
+ #
84
+
85
+ class Pid(DefaultTypedLoggerValue[int]):
86
+ @classmethod
87
+ def _default_value(cls) -> int:
88
+ return os.getpid()
89
+
90
+ class ProcessName(DefaultTypedLoggerValue[str]):
91
+ @classmethod
92
+ def _default_value(cls) -> ta.Union[str, AbsentTypedLoggerValue]:
93
+ if (mp := sys.modules.get('multiprocessing')) is None:
94
+ return ABSENT_TYPED_LOGGER_VALUE
95
+
96
+ # Errors may occur if multiprocessing has not finished loading yet - e.g. if a custom import hook causes
97
+ # third-party code to run when multiprocessing calls import. See issue 8200 for an example
98
+ try:
99
+ return mp.current_process().name
100
+ except Exception: # noqa
101
+ return ABSENT_TYPED_LOGGER_VALUE
102
+
103
+ #
104
+
105
+ class AsyncioTaskName(DefaultTypedLoggerValue[str]):
106
+ @classmethod
107
+ def _default_value(cls) -> ta.Union[str, AbsentTypedLoggerValue]:
108
+ if (asyncio := sys.modules.get('asyncio')) is None:
109
+ return ABSENT_TYPED_LOGGER_VALUE
110
+
111
+ try:
112
+ return asyncio.current_task().get_name()
113
+ except Exception: # noqa
114
+ return ABSENT_TYPED_LOGGER_VALUE
@@ -9,6 +9,7 @@ TODO:
9
9
  - can't disambiguate from str - can't coexist in bare union
10
10
  - factories being free MatchFns does more harm than good - in practice these are such big guns you want to write a
11
11
  class body if only ceremonially
12
+ - simple lite interop like inj - alt ObjMarshalerManager impl for Context
12
13
 
13
14
  See:
14
15
  - https://github.com/python-attrs/cattrs
omlish/os/atomics.py CHANGED
@@ -6,6 +6,7 @@ import shutil
6
6
  import tempfile
7
7
  import typing as ta
8
8
 
9
+ from ..lite.abstract import Abstract
9
10
  from ..lite.check import check
10
11
  from ..lite.strings import attr_repr
11
12
 
@@ -17,7 +18,7 @@ AtomicPathSwapState = ta.Literal['open', 'committed', 'aborted'] # ta.TypeAlias
17
18
  ##
18
19
 
19
20
 
20
- class AtomicPathSwap(abc.ABC):
21
+ class AtomicPathSwap(Abstract):
21
22
  def __init__(
22
23
  self,
23
24
  kind: AtomicPathSwapKind,
@@ -105,7 +106,7 @@ class AtomicPathSwap(abc.ABC):
105
106
  self.abort()
106
107
 
107
108
 
108
- class AtomicPathSwapping(abc.ABC):
109
+ class AtomicPathSwapping(Abstract):
109
110
  @abc.abstractmethod
110
111
  def begin_atomic_path_swap(
111
112
  self,
@@ -5,11 +5,13 @@ import sys
5
5
  import time
6
6
  import typing as ta
7
7
 
8
+ from ... import lang
9
+
8
10
 
9
11
  ##
10
12
 
11
13
 
12
- class Deathpact(abc.ABC):
14
+ class Deathpact(lang.Abstract):
13
15
  @abc.abstractmethod
14
16
  def poll(self) -> None:
15
17
  raise NotImplementedError
@@ -23,7 +25,7 @@ class NopDeathpact(Deathpact):
23
25
  ##
24
26
 
25
27
 
26
- class BaseDeathpact(Deathpact, abc.ABC):
28
+ class BaseDeathpact(Deathpact, lang.Abstract):
27
29
  def __init__(
28
30
  self,
29
31
  *,
omlish/os/forkhooks.py CHANGED
@@ -1,10 +1,10 @@
1
1
  # ruff: noqa: UP006 UP007 UP045
2
2
  # @omlish-lite
3
- import abc
4
3
  import os
5
4
  import threading
6
5
  import typing as ta
7
6
 
7
+ from ..lite.abstract import Abstract
8
8
  from ..lite.check import check
9
9
 
10
10
 
@@ -145,7 +145,7 @@ class _ForkHookManager:
145
145
  #
146
146
 
147
147
 
148
- class ForkHook(abc.ABC): # noqa
148
+ class ForkHook(Abstract):
149
149
  @ta.final
150
150
  def __new__(cls, *args, **kwargs): # noqa
151
151
  raise TypeError
@@ -27,6 +27,7 @@ import typing as ta
27
27
 
28
28
  from ...diag.lslocks import LslocksCommand
29
29
  from ...diag.lsof import LsofCommand
30
+ from ...lite.abstract import Abstract
30
31
  from ...lite.check import check
31
32
  from ...lite.timeouts import Timeout
32
33
  from ...lite.timeouts import TimeoutLike
@@ -37,7 +38,7 @@ from .pidfile import Pidfile
37
38
  ##
38
39
 
39
40
 
40
- class PidfilePinner(abc.ABC):
41
+ class PidfilePinner(Abstract):
41
42
  def __init__(
42
43
  self,
43
44
  *,