omlish 0.0.0.dev421__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/logs/callers.py +23 -4
- omlish/logs/levels.py +3 -0
- omlish/logs/protocol.py +21 -17
- 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-0.0.0.dev421.dist-info → omlish-0.0.0.dev422.dist-info}/METADATA +1 -1
- {omlish-0.0.0.dev421.dist-info → omlish-0.0.0.dev422.dist-info}/RECORD +15 -10
- {omlish-0.0.0.dev421.dist-info → omlish-0.0.0.dev422.dist-info}/WHEEL +0 -0
- {omlish-0.0.0.dev421.dist-info → omlish-0.0.0.dev422.dist-info}/entry_points.txt +0 -0
- {omlish-0.0.0.dev421.dist-info → omlish-0.0.0.dev422.dist-info}/licenses/LICENSE +0 -0
- {omlish-0.0.0.dev421.dist-info → omlish-0.0.0.dev422.dist-info}/top_level.txt +0 -0
omlish/__about__.py
CHANGED
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.
|
22
|
-
|
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(
|
30
|
-
|
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
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
|