omlish 0.0.0.dev421__py3-none-any.whl → 0.0.0.dev423__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 CHANGED
@@ -1,5 +1,5 @@
1
- __version__ = '0.0.0.dev421'
2
- __revision__ = 'e94a9ef0aba686505b9880c69a5e4dbd2621ad44'
1
+ __version__ = '0.0.0.dev423'
2
+ __revision__ = 'ab3e661e1a48e3d4bb4bacfd9112d4ce25b3359b'
3
3
 
4
4
 
5
5
  #
omlish/logs/callers.py CHANGED
@@ -1,6 +1,7 @@
1
1
  # ruff: noqa: UP006 UP007 UP045
2
2
  # @omlish-lite
3
3
  import io
4
+ import os.path
4
5
  import sys
5
6
  import traceback
6
7
  import types
@@ -16,18 +17,36 @@ class LoggingCaller(ta.NamedTuple):
16
17
  func: str
17
18
  sinfo: ta.Optional[str]
18
19
 
20
+ @classmethod
21
+ def is_internal_frame(cls, frame: types.FrameType) -> bool:
22
+ filename = os.path.normcase(frame.f_code.co_filename)
23
+
24
+ # https://github.com/python/cpython/commit/5ca6d7469be53960843df39bb900e9c3359f127f
25
+ if 'importlib' in filename and '_bootstrap' in filename:
26
+ return True
27
+
28
+ return False
29
+
19
30
  @classmethod
20
31
  def find_frame(cls, ofs: int = 0) -> types.FrameType:
21
- f: ta.Any = sys._getframe(2 + ofs) # noqa
22
- while hasattr(f, 'f_code'):
32
+ f: ta.Optional[types.FrameType] = sys._getframe(2 + ofs) # noqa
33
+
34
+ while f is not None and hasattr(f, 'f_code'):
23
35
  if f.f_code.co_filename != __file__:
24
36
  return f
37
+
25
38
  f = f.f_back
39
+
26
40
  raise RuntimeError
27
41
 
28
42
  @classmethod
29
- def find(cls, stack_info: bool = False) -> 'LoggingCaller':
30
- f = cls.find_frame(1)
43
+ def find(
44
+ cls,
45
+ ofs: int = 0,
46
+ *,
47
+ stack_info: bool = False,
48
+ ) -> 'LoggingCaller':
49
+ f = cls.find_frame(ofs + 1)
31
50
  # TODO: ('(unknown file)', 0, '(unknown function)', None) ?
32
51
 
33
52
  sinfo = None
omlish/logs/levels.py CHANGED
@@ -2,3 +2,6 @@
2
2
 
3
3
 
4
4
  LogLevel = int # ta.TypeAlias
5
+
6
+
7
+ ##
omlish/logs/protocol.py CHANGED
@@ -67,23 +67,23 @@ class AnyAbstractLogging(abc.ABC, ta.Generic[T]):
67
67
 
68
68
  #
69
69
 
70
- def debug(self, msg: str, *args: ta.Any, **kwargs: ta.Any) -> T:
71
- return self.log(logging.DEBUG, msg, *args, **kwargs)
70
+ def debug(self, msg: str, *args: ta.Any, _logging_stack_offset: int = 0, **kwargs: ta.Any) -> T:
71
+ return self.log(logging.DEBUG, msg, *args, _logging_stack_offset=_logging_stack_offset + 1, **kwargs)
72
72
 
73
- def info(self, msg: str, *args: ta.Any, **kwargs: ta.Any) -> T:
74
- return self.log(logging.INFO, msg, *args, **kwargs)
73
+ def info(self, msg: str, *args: ta.Any, _logging_stack_offset: int = 0, **kwargs: ta.Any) -> T:
74
+ return self.log(logging.INFO, msg, *args, _logging_stack_offset=_logging_stack_offset + 1, **kwargs)
75
75
 
76
- def warning(self, msg: str, *args: ta.Any, **kwargs: ta.Any) -> T:
77
- return self.log(logging.WARNING, msg, *args, **kwargs)
76
+ def warning(self, msg: str, *args: ta.Any, _logging_stack_offset: int = 0, **kwargs: ta.Any) -> T:
77
+ return self.log(logging.WARNING, msg, *args, _logging_stack_offset=_logging_stack_offset + 1, **kwargs)
78
78
 
79
- def error(self, msg: str, *args: ta.Any, **kwargs: ta.Any) -> T:
80
- return self.log(logging.ERROR, msg, *args, **kwargs)
79
+ def error(self, msg: str, *args: ta.Any, _logging_stack_offset: int = 0, **kwargs: ta.Any) -> T:
80
+ return self.log(logging.ERROR, msg, *args, _logging_stack_offset=_logging_stack_offset + 1, **kwargs)
81
81
 
82
- def exception(self, msg: str, *args: ta.Any, exc_info: bool = True, **kwargs: ta.Any) -> T:
83
- return self.error(msg, *args, exc_info=exc_info, **kwargs)
82
+ def exception(self, msg: str, *args: ta.Any, exc_info: bool = True, _logging_stack_offset: int = 0, **kwargs: ta.Any) -> T: # noqa
83
+ return self.error(msg, *args, exc_info=exc_info, _logging_stack_offset=_logging_stack_offset + 1, **kwargs) # noqa
84
84
 
85
- def critical(self, msg: str, *args: ta.Any, **kwargs: ta.Any) -> T:
86
- return self.log(logging.CRITICAL, msg, *args, **kwargs)
85
+ def critical(self, msg: str, *args: ta.Any, _logging_stack_offset: int = 0, **kwargs: ta.Any) -> T:
86
+ return self.log(logging.CRITICAL, msg, *args, _logging_stack_offset=_logging_stack_offset + 1, **kwargs)
87
87
 
88
88
  @abc.abstractmethod
89
89
  def log(
@@ -94,16 +94,17 @@ class AnyAbstractLogging(abc.ABC, ta.Generic[T]):
94
94
  exc_info: ta.Any = None,
95
95
  extra: ta.Any = None,
96
96
  stack_info: bool = False,
97
+ _logging_stack_offset: int = 0,
97
98
  ) -> T:
98
99
  raise NotImplementedError
99
100
 
100
101
 
101
102
  class AbstractLogging(AnyAbstractLogging[None], abc.ABC):
102
- def log(self, level: LogLevel, msg: str, *args: ta.Any, **kwargs: ta.Any) -> None:
103
+ def log(self, level: LogLevel, msg: str, *args: ta.Any, _logging_stack_offset: int = 0, **kwargs: ta.Any) -> None:
103
104
  if not isinstance(level, int):
104
105
  raise TypeError('Level must be an integer.')
105
106
  if self.is_enabled_for(level):
106
- self._log(level, msg, args, **kwargs)
107
+ self._log(level, msg, args, _logging_stack_offset=_logging_stack_offset + 1, **kwargs)
107
108
 
108
109
  @abc.abstractmethod
109
110
  def _log(
@@ -115,16 +116,17 @@ class AbstractLogging(AnyAbstractLogging[None], abc.ABC):
115
116
  exc_info: ta.Any = None,
116
117
  extra: ta.Any = None,
117
118
  stack_info: bool = False,
119
+ _logging_stack_offset: int = 0,
118
120
  ) -> None:
119
121
  raise NotImplementedError
120
122
 
121
123
 
122
124
  class AbstractAsyncLogging(AnyAbstractLogging[ta.Awaitable[None]], abc.ABC):
123
- async def log(self, level: LogLevel, msg: str, *args: ta.Any, **kwargs: ta.Any) -> None:
125
+ async def log(self, level: LogLevel, msg: str, *args: ta.Any, _logging_stack_offset: int = 0, **kwargs: ta.Any) -> None: # noqa
124
126
  if not isinstance(level, int):
125
127
  raise TypeError('Level must be an integer.')
126
128
  if self.is_enabled_for(level):
127
- await self._log(level, msg, args, **kwargs)
129
+ await self._log(level, msg, args, _logging_stack_offset=_logging_stack_offset + 1, **kwargs)
128
130
 
129
131
  @abc.abstractmethod
130
132
  def _log(
@@ -136,6 +138,7 @@ class AbstractAsyncLogging(AnyAbstractLogging[ta.Awaitable[None]], abc.ABC):
136
138
  exc_info: ta.Any = None,
137
139
  extra: ta.Any = None,
138
140
  stack_info: bool = False,
141
+ _logging_stack_offset: int = 0,
139
142
  ) -> ta.Awaitable[None]:
140
143
  raise NotImplementedError
141
144
 
@@ -189,8 +192,9 @@ class StdlibLogging(AbstractLogging):
189
192
  exc_info: ta.Any = None,
190
193
  extra: ta.Any = None,
191
194
  stack_info: bool = False,
195
+ _logging_stack_offset: int = 0,
192
196
  ) -> None:
193
- caller = LoggingCaller.find(stack_info)
197
+ caller = LoggingCaller.find(_logging_stack_offset, stack_info=stack_info)
194
198
 
195
199
  if exc_info:
196
200
  if isinstance(exc_info, BaseException):
File without changes
@@ -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