omlish 0.0.0.dev429__py3-none-any.whl → 0.0.0.dev431__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.dev429'
2
- __revision__ = 'aec560601e4f8ecdc171e4341c2b17e996a0ef91'
1
+ __version__ = '0.0.0.dev431'
2
+ __revision__ = '2294dfec3fc11ecdc80e86c2f6912e3c650d5c9c'
3
3
 
4
4
 
5
5
  #
@@ -104,7 +104,7 @@ class AsyncIoProxy:
104
104
  __proxied_cls__: ta.ClassVar[type]
105
105
 
106
106
  def __init_subclass__(cls, *, proxied_cls=None, **kwargs): # noqa
107
- super().__init_subclass__()
107
+ super().__init_subclass__(**kwargs)
108
108
 
109
109
  cls.__proxied_cls__ = check.isinstance(proxied_cls, (type, None))
110
110
 
@@ -1,11 +1,17 @@
1
- from .executors import ( # noqa
2
- ImmediateExecutor,
3
- new_executor,
4
- )
5
-
6
- from .futures import ( # noqa
7
- FutureError,
8
- FutureTimeoutError,
9
- wait_futures,
10
- wait_dependent_futures,
11
- )
1
+ from .. import lang as _lang
2
+
3
+
4
+ with _lang.auto_proxy_init(globals()):
5
+ ##
6
+
7
+ from .executors import ( # noqa
8
+ ImmediateExecutor,
9
+ new_executor,
10
+ )
11
+
12
+ from .futures import ( # noqa
13
+ FutureError,
14
+ FutureTimeoutError,
15
+ wait_futures,
16
+ wait_dependent_futures,
17
+ )
omlish/funcs/match.py CHANGED
@@ -208,7 +208,7 @@ class MatchFnClass(MatchFn[P, T]):
208
208
  return mf
209
209
 
210
210
  def __init_subclass__(cls, strict: bool = False, **kwargs: ta.Any) -> None:
211
- super().__init_subclass__()
211
+ super().__init_subclass__(**kwargs)
212
212
 
213
213
  if '_cls_match_fn' in cls.__dict__:
214
214
  raise AttributeError('_cls_match_fn')
omlish/lang/asyncs.py CHANGED
@@ -19,9 +19,7 @@ def as_async(fn: ta.Callable[P, T], *, wrap: bool = False) -> ta.Callable[P, ta.
19
19
  ##
20
20
 
21
21
 
22
- async def async_list(
23
- ai: ta.AsyncIterable[T],
24
- ) -> list[T]:
22
+ async def async_list(ai: ta.AsyncIterable[T]) -> list[T]:
25
23
  """Simply eagerly reads the full contents of a function call returning an async iterator."""
26
24
 
27
25
  return [v async for v in ai]
@@ -30,9 +28,7 @@ async def async_list(
30
28
  ##
31
29
 
32
30
 
33
- def sync_await(
34
- aw: ta.Awaitable[T],
35
- ) -> T:
31
+ def sync_await(aw: ta.Awaitable[T]) -> T:
36
32
  """
37
33
  Allows for the synchronous execution of async functions which will never actually *externally* await anything. These
38
34
  functions are allowed to await any number of other functions - including contextmanagers and generators - so long as
@@ -644,9 +644,10 @@ def auto_proxy_init(
644
644
  update_exports: bool = False,
645
645
  ) -> ta.Iterator[AutoProxyInit]:
646
646
  """
647
- This is a bit extreme - use sparingly. It relies on an interpreter-global import lock, but much of the ecosystem
648
- implicitly does anyway. It further relies on temporarily patching `__builtins__.__import__`, but could be switched
649
- to use any number of other import hooks.
647
+ This is a bit extreme, but worth it. For simplicity, it currently relies on temporarily patching
648
+ `__builtins__.__import__` for the duration of its context manager, but it can be switched to use any number of other
649
+ import hooks (like `sys.meta_path`). It does not rely on any permanent modification to import machinery, only for
650
+ the duration of its capture.
650
651
  """
651
652
 
652
653
  inst = AutoProxyInit(
omlish/lite/attrops.py CHANGED
@@ -285,8 +285,6 @@ class AttrOps(ta.Generic[T]):
285
285
  self._eq = _eq
286
286
  return _eq
287
287
 
288
- #
289
-
290
288
  @property
291
289
  def hash_eq(self) -> ta.Tuple[
292
290
  ta.Callable[[T], int],
@@ -294,6 +292,8 @@ class AttrOps(ta.Generic[T]):
294
292
  ]:
295
293
  return (self.hash, self.eq)
296
294
 
295
+ #
296
+
297
297
  @property
298
298
  def repr_hash_eq(self) -> ta.Tuple[
299
299
  ta.Callable[[T], str],
@@ -304,20 +304,25 @@ class AttrOps(ta.Generic[T]):
304
304
 
305
305
  #
306
306
 
307
+ class NOT_SET: # noqa
308
+ def __new__(cls, *args, **kwargs): # noqa
309
+ raise TypeError
310
+
307
311
  def install(
308
312
  self,
309
313
  locals_dct: ta.MutableMapping[str, ta.Any],
310
314
  *,
311
- all: bool = False, # noqa
312
- repr: bool = False, # noqa
313
- hash: bool = False, # noqa
314
- eq: bool = False,
315
+ repr: ta.Union[bool, ta.Type[NOT_SET]] = NOT_SET, # noqa
316
+ hash: ta.Union[bool, ta.Type[NOT_SET]] = NOT_SET, # noqa
317
+ eq: ta.Union[bool, ta.Type[NOT_SET]] = NOT_SET,
315
318
  ) -> 'AttrOps[T]':
316
- if repr or all:
319
+ if all(a is self.NOT_SET for a in (repr, hash, eq)):
320
+ repr = hash = eq = True # noqa
321
+ if repr:
317
322
  locals_dct.update(__repr__=self.repr)
318
- if hash or all:
323
+ if hash:
319
324
  locals_dct.update(__hash__=self.hash)
320
- if eq or all:
325
+ if eq:
321
326
  locals_dct.update(__eq__=self.eq)
322
327
  return self
323
328
 
omlish/logs/all.py CHANGED
@@ -17,6 +17,10 @@ with _lang.auto_proxy_init(globals()):
17
17
  JsonLoggingFormatter,
18
18
  )
19
19
 
20
+ from .std.loggers import ( # noqa
21
+ StdLogger,
22
+ )
23
+
20
24
  from .std.noisy import ( # noqa
21
25
  silence_noisy_loggers,
22
26
  )
@@ -26,8 +30,27 @@ with _lang.auto_proxy_init(globals()):
26
30
  ProxyLoggingHandler,
27
31
  )
28
32
 
29
- from .callers import ( # noqa
30
- LoggingCaller,
33
+ from .std.records import ( # noqa
34
+ LoggingContextLogRecord,
35
+ )
36
+
37
+ from .base import ( # noqa
38
+ AnyLogger,
39
+ Logger,
40
+ AsyncLogger,
41
+
42
+ AnyNopLogger,
43
+ NopLogger,
44
+ AsyncNopLogger,
45
+ )
46
+
47
+ from .contexts import ( # noqa
48
+ LoggingContext,
49
+ )
50
+
51
+ from .infos import ( # noqa
52
+ LoggingContextInfo,
53
+ LoggingContextInfos,
31
54
  )
32
55
 
33
56
  from .levels import ( # noqa
@@ -59,3 +82,7 @@ with _lang.auto_proxy_init(globals()):
59
82
 
60
83
  error_logging,
61
84
  )
85
+
86
+ from .warnings import ( # noqa
87
+ LoggingSetupWarning,
88
+ )
omlish/logs/base.py CHANGED
@@ -21,7 +21,6 @@ LoggingMsgFn = ta.Callable[[], ta.Union[str, tuple]] # ta.TypeAlias
21
21
 
22
22
 
23
23
  class AnyLogger(Abstract, ta.Generic[T]):
24
- @ta.final
25
24
  def is_enabled_for(self, level: LogLevel) -> bool:
26
25
  return level >= self.get_effective_level()
27
26
 
@@ -167,36 +166,6 @@ class AnyLogger(Abstract, ta.Generic[T]):
167
166
 
168
167
  ##
169
168
 
170
- @classmethod
171
- def _prepare_msg_args(cls, msg: ta.Union[str, tuple, LoggingMsgFn], *args: ta.Any) -> ta.Tuple[str, tuple]:
172
- if callable(msg):
173
- if args:
174
- raise TypeError(f'Must not provide both a message function and args: {msg=} {args=}')
175
- x = msg()
176
- if isinstance(x, str):
177
- return x, ()
178
- elif isinstance(x, tuple):
179
- if x:
180
- return x[0], x[1:]
181
- else:
182
- return '', ()
183
- else:
184
- raise TypeError(x)
185
-
186
- elif isinstance(msg, tuple):
187
- if args:
188
- raise TypeError(f'Must not provide both a tuple message and args: {msg=} {args=}')
189
- if msg:
190
- return msg[0], msg[1:]
191
- else:
192
- return '', ()
193
-
194
- elif isinstance(msg, str):
195
- return msg, args
196
-
197
- else:
198
- raise TypeError(msg)
199
-
200
169
  @abc.abstractmethod
201
170
  def _log(self, ctx: CaptureLoggingContext, msg: ta.Union[str, tuple, LoggingMsgFn], *args: ta.Any, **kwargs: ta.Any) -> T: # noqa
202
171
  raise NotImplementedError
@@ -220,7 +189,7 @@ class AsyncLogger(AnyLogger[ta.Awaitable[None]], Abstract):
220
189
  class AnyNopLogger(AnyLogger[T], Abstract):
221
190
  @ta.final
222
191
  def get_effective_level(self) -> LogLevel:
223
- return 999
192
+ return -999
224
193
 
225
194
 
226
195
  @ta.final
omlish/logs/contexts.py CHANGED
@@ -1,94 +1,54 @@
1
1
  # ruff: noqa: UP006 UP007 UP045 UP046
2
2
  # @omlish-lite
3
3
  import abc
4
- import sys
5
4
  import time
6
- import types
7
5
  import typing as ta
8
6
 
9
7
  from ..lite.abstract import Abstract
10
- from .callers import LoggingCaller
11
- from .infos import LoggingAsyncioTaskInfo
12
- from .infos import LoggingMultiprocessingInfo
13
- from .infos import LoggingProcessInfo
14
- from .infos import LoggingSourceFileInfo
15
- from .infos import LoggingThreadInfo
8
+ from .infos import LoggingContextInfo
9
+ from .infos import LoggingContextInfos
10
+ from .infos import LoggingExcInfoArg
11
+ from .infos import LoggingMsgFn
16
12
  from .levels import LogLevel
17
- from .levels import NamedLogLevel
18
- from .times import LoggingTimeFields
19
13
 
20
14
 
21
- LoggingExcInfoTuple = ta.Tuple[ta.Type[BaseException], BaseException, ta.Optional[types.TracebackType]] # ta.TypeAlias
22
- LoggingExcInfo = ta.Union[BaseException, LoggingExcInfoTuple] # ta.TypeAlias
23
- LoggingExcInfoArg = ta.Union[LoggingExcInfo, bool, None] # ta.TypeAlias
15
+ LoggingContextInfoT = ta.TypeVar('LoggingContextInfoT', bound=LoggingContextInfo)
24
16
 
25
17
 
26
18
  ##
27
19
 
28
20
 
29
21
  class LoggingContext(Abstract):
30
- @property
31
22
  @abc.abstractmethod
32
- def level(self) -> NamedLogLevel:
23
+ def get_info(self, ty: ta.Type[LoggingContextInfoT]) -> ta.Optional[LoggingContextInfoT]:
33
24
  raise NotImplementedError
34
25
 
35
- #
36
-
37
- @property
38
- @abc.abstractmethod
39
- def time_ns(self) -> int:
40
- raise NotImplementedError
41
-
42
- @property
43
- @abc.abstractmethod
44
- def times(self) -> LoggingTimeFields:
45
- raise NotImplementedError
46
-
47
- #
26
+ @ta.final
27
+ def __getitem__(self, ty: ta.Type[LoggingContextInfoT]) -> ta.Optional[LoggingContextInfoT]:
28
+ return self.get_info(ty)
48
29
 
49
- @property
50
- @abc.abstractmethod
51
- def exc_info(self) -> ta.Optional[LoggingExcInfo]:
52
- raise NotImplementedError
30
+ @ta.final
31
+ def must_get_info(self, ty: ta.Type[LoggingContextInfoT]) -> LoggingContextInfoT:
32
+ if (info := self.get_info(ty)) is None:
33
+ raise TypeError(f'LoggingContextInfo absent: {ty}')
34
+ return info
53
35
 
54
- @property
55
- @abc.abstractmethod
56
- def exc_info_tuple(self) -> ta.Optional[LoggingExcInfoTuple]:
57
- raise NotImplementedError
36
+ ##
58
37
 
59
- #
60
38
 
39
+ class CaptureLoggingContext(LoggingContext, Abstract):
61
40
  @abc.abstractmethod
62
- def caller(self) -> ta.Optional[LoggingCaller]:
63
- raise NotImplementedError
41
+ def set_basic(
42
+ self,
43
+ name: str,
64
44
 
65
- @abc.abstractmethod
66
- def source_file(self) -> ta.Optional[LoggingSourceFileInfo]:
45
+ msg: ta.Union[str, tuple, LoggingMsgFn],
46
+ args: tuple,
47
+ ) -> 'CaptureLoggingContext':
67
48
  raise NotImplementedError
68
49
 
69
50
  #
70
51
 
71
- @abc.abstractmethod
72
- def thread(self) -> ta.Optional[LoggingThreadInfo]:
73
- raise NotImplementedError
74
-
75
- @abc.abstractmethod
76
- def process(self) -> ta.Optional[LoggingProcessInfo]:
77
- raise NotImplementedError
78
-
79
- @abc.abstractmethod
80
- def multiprocessing(self) -> ta.Optional[LoggingMultiprocessingInfo]:
81
- raise NotImplementedError
82
-
83
- @abc.abstractmethod
84
- def asyncio_task(self) -> ta.Optional[LoggingAsyncioTaskInfo]:
85
- raise NotImplementedError
86
-
87
-
88
- ##
89
-
90
-
91
- class CaptureLoggingContext(LoggingContext, Abstract):
92
52
  class AlreadyCapturedError(Exception):
93
53
  pass
94
54
 
@@ -119,80 +79,50 @@ class CaptureLoggingContextImpl(CaptureLoggingContext):
119
79
 
120
80
  exc_info: LoggingExcInfoArg = False,
121
81
 
122
- caller: ta.Union[LoggingCaller, ta.Type[NOT_SET], None] = NOT_SET,
82
+ caller: ta.Union[LoggingContextInfos.Caller, ta.Type[NOT_SET], None] = NOT_SET,
123
83
  stack_offset: int = 0,
124
84
  stack_info: bool = False,
125
85
  ) -> None:
126
- self._level: NamedLogLevel = level if level.__class__ is NamedLogLevel else NamedLogLevel(level) # type: ignore[assignment] # noqa
127
-
128
- #
86
+ # TODO: Name, Msg, Extra
129
87
 
130
88
  if time_ns is None:
131
89
  time_ns = time.time_ns()
132
- self._time_ns: int = time_ns
133
-
134
- #
135
-
136
- if exc_info is True:
137
- sys_exc_info = sys.exc_info()
138
- if sys_exc_info[0] is not None:
139
- exc_info = sys_exc_info
140
- else:
141
- exc_info = None
142
- elif exc_info is False:
143
- exc_info = None
144
-
145
- if exc_info is not None:
146
- self._exc_info: ta.Optional[LoggingExcInfo] = exc_info
147
- if isinstance(exc_info, BaseException):
148
- self._exc_info_tuple: ta.Optional[LoggingExcInfoTuple] = (type(exc_info), exc_info, exc_info.__traceback__) # noqa
149
- else:
150
- self._exc_info_tuple = exc_info
151
90
 
152
- #
91
+ self._infos: ta.Dict[ta.Type[LoggingContextInfo], LoggingContextInfo] = {}
92
+ self._set_info(
93
+ LoggingContextInfos.Level.build(level),
94
+ LoggingContextInfos.Time.build(time_ns),
95
+ LoggingContextInfos.Exc.build(exc_info),
96
+ )
153
97
 
154
98
  if caller is not CaptureLoggingContextImpl.NOT_SET:
155
- self._caller = caller # type: ignore[assignment]
99
+ self._infos[LoggingContextInfos.Caller] = caller
156
100
  else:
157
101
  self._stack_offset = stack_offset
158
102
  self._stack_info = stack_info
159
103
 
160
- ##
161
-
162
- @property
163
- def level(self) -> NamedLogLevel:
164
- return self._level
165
-
166
- #
167
-
168
- @property
169
- def time_ns(self) -> int:
170
- return self._time_ns
171
-
172
- _times: LoggingTimeFields
173
-
174
- @property
175
- def times(self) -> LoggingTimeFields:
176
- try:
177
- return self._times
178
- except AttributeError:
179
- pass
180
-
181
- times = self._times = LoggingTimeFields.build(self.time_ns)
182
- return times
104
+ def _set_info(self, *infos: ta.Optional[LoggingContextInfo]) -> 'CaptureLoggingContextImpl':
105
+ for info in infos:
106
+ if info is not None:
107
+ self._infos[type(info)] = info
108
+ return self
183
109
 
184
- #
110
+ def get_info(self, ty: ta.Type[LoggingContextInfoT]) -> ta.Optional[LoggingContextInfoT]:
111
+ return self._infos.get(ty)
185
112
 
186
- _exc_info: ta.Optional[LoggingExcInfo] = None
187
- _exc_info_tuple: ta.Optional[LoggingExcInfoTuple] = None
113
+ ##
188
114
 
189
- @property
190
- def exc_info(self) -> ta.Optional[LoggingExcInfo]:
191
- return self._exc_info
115
+ def set_basic(
116
+ self,
117
+ name: str,
192
118
 
193
- @property
194
- def exc_info_tuple(self) -> ta.Optional[LoggingExcInfoTuple]:
195
- return self._exc_info_tuple
119
+ msg: ta.Union[str, tuple, LoggingMsgFn],
120
+ args: tuple,
121
+ ) -> 'CaptureLoggingContextImpl':
122
+ return self._set_info(
123
+ LoggingContextInfos.Name(name),
124
+ LoggingContextInfos.Msg.build(msg, *args),
125
+ )
196
126
 
197
127
  ##
198
128
 
@@ -206,71 +136,25 @@ class CaptureLoggingContextImpl(CaptureLoggingContext):
206
136
 
207
137
  _has_captured: bool = False
208
138
 
209
- _caller: ta.Optional[LoggingCaller]
210
- _source_file: ta.Optional[LoggingSourceFileInfo]
211
-
212
- _thread: ta.Optional[LoggingThreadInfo]
213
- _process: ta.Optional[LoggingProcessInfo]
214
- _multiprocessing: ta.Optional[LoggingMultiprocessingInfo]
215
- _asyncio_task: ta.Optional[LoggingAsyncioTaskInfo]
216
-
217
139
  def capture(self) -> None:
218
140
  if self._has_captured:
219
141
  raise CaptureLoggingContextImpl.AlreadyCapturedError
220
142
  self._has_captured = True
221
143
 
222
- if not hasattr(self, '_caller'):
223
- self._caller = LoggingCaller.find(
144
+ if LoggingContextInfos.Caller not in self._infos:
145
+ self._set_info(LoggingContextInfos.Caller.build(
224
146
  self._stack_offset + 1,
225
147
  stack_info=self._stack_info,
226
- )
227
-
228
- if (caller := self._caller) is not None:
229
- self._source_file = LoggingSourceFileInfo.build(caller.file_path)
230
- else:
231
- self._source_file = None
232
-
233
- self._thread = LoggingThreadInfo.build()
234
- self._process = LoggingProcessInfo.build()
235
- self._multiprocessing = LoggingMultiprocessingInfo.build()
236
- self._asyncio_task = LoggingAsyncioTaskInfo.build()
237
-
238
- #
239
-
240
- def caller(self) -> ta.Optional[LoggingCaller]:
241
- try:
242
- return self._caller
243
- except AttributeError:
244
- raise CaptureLoggingContext.NotCapturedError from None
245
-
246
- def source_file(self) -> ta.Optional[LoggingSourceFileInfo]:
247
- try:
248
- return self._source_file
249
- except AttributeError:
250
- raise CaptureLoggingContext.NotCapturedError from None
251
-
252
- #
253
-
254
- def thread(self) -> ta.Optional[LoggingThreadInfo]:
255
- try:
256
- return self._thread
257
- except AttributeError:
258
- raise CaptureLoggingContext.NotCapturedError from None
259
-
260
- def process(self) -> ta.Optional[LoggingProcessInfo]:
261
- try:
262
- return self._process
263
- except AttributeError:
264
- raise CaptureLoggingContext.NotCapturedError from None
265
-
266
- def multiprocessing(self) -> ta.Optional[LoggingMultiprocessingInfo]:
267
- try:
268
- return self._multiprocessing
269
- except AttributeError:
270
- raise CaptureLoggingContext.NotCapturedError from None
271
-
272
- def asyncio_task(self) -> ta.Optional[LoggingAsyncioTaskInfo]:
273
- try:
274
- return self._asyncio_task
275
- except AttributeError:
276
- raise CaptureLoggingContext.NotCapturedError from None
148
+ ))
149
+
150
+ if (caller := self[LoggingContextInfos.Caller]) is not None:
151
+ self._set_info(LoggingContextInfos.SourceFile.build(
152
+ caller.file_path,
153
+ ))
154
+
155
+ self._set_info(
156
+ LoggingContextInfos.Thread.build(),
157
+ LoggingContextInfos.Process.build(),
158
+ LoggingContextInfos.Multiprocessing.build(),
159
+ LoggingContextInfos.AsyncioTask.build(),
160
+ )