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.
- omlish/__about__.py +2 -2
- omlish/asyncs/bluelet/core.py +2 -2
- omlish/asyncs/bluelet/events.py +4 -3
- omlish/asyncs/bluelet/files.py +2 -2
- omlish/asyncs/bluelet/sockets.py +2 -2
- omlish/collections/frozen.py +1 -1
- omlish/collections/kv/base.py +1 -1
- omlish/collections/multimaps.py +1 -1
- omlish/collections/persistent/treapmap.py +2 -1
- omlish/concurrent/threadlets.py +2 -2
- omlish/configs/formats.py +5 -4
- omlish/configs/processing/flattening.py +2 -1
- omlish/configs/processing/rewriting.py +2 -2
- omlish/configs/shadow.py +3 -2
- omlish/daemons/spawning.py +2 -2
- omlish/daemons/targets.py +1 -1
- omlish/daemons/waiting.py +2 -1
- omlish/dataclasses/impl/generation/base.py +3 -2
- omlish/dataclasses/impl/generation/compilation.py +2 -1
- omlish/dataclasses/impl/generation/ops.py +2 -2
- omlish/dataclasses/impl/generation/processor.py +1 -1
- omlish/dataclasses/metaclass/meta.py +1 -0
- omlish/dataclasses/tools/static.py +5 -1
- omlish/formats/dotenv.py +3 -1
- omlish/formats/logfmt.py +111 -0
- omlish/formats/yaml.py +1 -1
- omlish/funcs/builders.py +2 -1
- omlish/funcs/match.py +1 -1
- omlish/funcs/pairs.py +41 -23
- omlish/funcs/pipes.py +3 -1
- omlish/http/asgi.py +2 -1
- omlish/http/coro/client/io.py +3 -2
- omlish/http/coro/server/server.py +2 -2
- omlish/http/handlers.py +2 -1
- omlish/http/jwt.py +1 -1
- omlish/http/parsing.py +2 -2
- omlish/io/compress/base.py +3 -2
- omlish/io/coro/readers.py +4 -3
- omlish/io/fdio/handlers.py +3 -2
- omlish/io/fdio/pollers.py +3 -1
- omlish/lang/__init__.py +20 -8
- omlish/lang/attrs.py +3 -1
- omlish/lang/casing.py +3 -1
- omlish/lang/classes/abstract.py +35 -96
- omlish/lang/classes/virtual.py +2 -2
- omlish/lang/contextmanagers.py +6 -4
- omlish/lang/generators.py +2 -2
- omlish/lang/iterables.py +6 -6
- omlish/lang/objects.py +0 -58
- omlish/lang/outcomes.py +3 -1
- omlish/lang/typing.py +5 -24
- omlish/lite/abstract.py +119 -0
- omlish/lite/contextmanagers.py +4 -1
- omlish/lite/inject.py +9 -9
- omlish/lite/marshal.py +230 -114
- omlish/lite/maybes.py +3 -1
- omlish/lite/maysync.py +4 -2
- omlish/lite/objects.py +81 -0
- omlish/lite/reflect.py +0 -15
- omlish/lite/timeouts.py +3 -1
- omlish/lite/wrappers.py +23 -0
- omlish/logs/abc.py +21 -5
- omlish/logs/all.py +14 -3
- omlish/logs/callers.py +23 -4
- omlish/logs/configs.py +13 -10
- omlish/logs/levels.py +7 -0
- omlish/logs/protocol.py +84 -42
- omlish/logs/typed/__init__.py +0 -0
- omlish/logs/typed/bindings.py +537 -0
- omlish/logs/typed/contexts.py +138 -0
- omlish/logs/typed/types.py +484 -0
- omlish/logs/typed/values.py +114 -0
- omlish/marshal/__init__.py +1 -0
- omlish/os/atomics.py +3 -2
- omlish/os/deathpacts/base.py +4 -2
- omlish/os/forkhooks.py +2 -2
- omlish/os/pidfiles/pinning.py +2 -1
- omlish/reflect/types.py +4 -3
- omlish/secrets/crypto.py +1 -1
- omlish/sockets/bind.py +2 -1
- omlish/sockets/handlers.py +3 -2
- omlish/sockets/server/handlers.py +2 -1
- omlish/sockets/server/server.py +4 -3
- omlish/sql/api/base.py +2 -2
- omlish/subprocesses/asyncs.py +2 -1
- omlish/subprocesses/base.py +2 -2
- omlish/subprocesses/maysync.py +1 -2
- omlish/subprocesses/run.py +2 -1
- omlish/subprocesses/sync.py +2 -1
- omlish/term/coloring.py +3 -1
- omlish/testing/pytest/plugins/asyncs/backends/base.py +3 -1
- omlish/testing/unittest/loading.py +2 -2
- omlish/text/asdl.py +4 -3
- {omlish-0.0.0.dev420.dist-info → omlish-0.0.0.dev422.dist-info}/METADATA +1 -1
- {omlish-0.0.0.dev420.dist-info → omlish-0.0.0.dev422.dist-info}/RECORD +99 -89
- {omlish-0.0.0.dev420.dist-info → omlish-0.0.0.dev422.dist-info}/WHEEL +0 -0
- {omlish-0.0.0.dev420.dist-info → omlish-0.0.0.dev422.dist-info}/entry_points.txt +0 -0
- {omlish-0.0.0.dev420.dist-info → omlish-0.0.0.dev422.dist-info}/licenses/LICENSE +0 -0
- {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))
|