omlish 0.0.0.dev424__py3-none-any.whl → 0.0.0.dev425__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (96) hide show
  1. omlish/__about__.py +3 -3
  2. omlish/dataclasses/impl/configs.py +2 -1
  3. omlish/formats/json/stream/lexing.py +8 -0
  4. omlish/formats/json/stream/utils.py +3 -0
  5. omlish/formats/json5/streams.py +22 -0
  6. omlish/lang/__init__.py +3 -1
  7. omlish/lang/asyncs.py +12 -0
  8. omlish/lang/functions.py +0 -11
  9. omlish/lang/lazyglobals.py +27 -5
  10. omlish/lang/maysync.py +2 -2
  11. omlish/lifecycles/contextmanagers.py +1 -2
  12. omlish/lifecycles/controller.py +1 -2
  13. omlish/lite/asyncs.py +15 -0
  14. omlish/lite/timing.py +2 -2
  15. omlish/logs/all.py +23 -34
  16. omlish/logs/base.py +248 -0
  17. omlish/logs/callers.py +21 -15
  18. omlish/logs/infos.py +105 -0
  19. omlish/logs/levels.py +64 -0
  20. omlish/logs/protocols.py +31 -0
  21. omlish/logs/standard.py +12 -11
  22. omlish/logs/std/adapters.py +41 -0
  23. omlish/logs/std/configs.py +29 -0
  24. omlish/logs/{filters.py → std/filters.py} +1 -1
  25. omlish/logs/{handlers.py → std/handlers.py} +1 -1
  26. omlish/logs/{json.py → std/json.py} +2 -2
  27. omlish/logs/{proxy.py → std/proxy.py} +3 -3
  28. omlish/logs/std/records.py +286 -0
  29. omlish/logs/times.py +89 -0
  30. omlish/logs/typed/bindings.py +24 -0
  31. omlish/logs/utils.py +60 -4
  32. omlish/logs/warnings.py +8 -0
  33. omlish/manifests/loading.py +1 -1
  34. omlish/os/journald.py +3 -3
  35. omlish/testing/pytest/plugins/skips.py +0 -4
  36. {omlish-0.0.0.dev424.dist-info → omlish-0.0.0.dev425.dist-info}/METADATA +1 -1
  37. {omlish-0.0.0.dev424.dist-info → omlish-0.0.0.dev425.dist-info}/RECORD +44 -86
  38. omlish/defs.py +0 -216
  39. omlish/dispatch/_dispatch2.py +0 -69
  40. omlish/dispatch/_dispatch3.py +0 -108
  41. omlish/dynamic.py +0 -219
  42. omlish/formats/json/Json.g4 +0 -77
  43. omlish/formats/json/_antlr/JsonLexer.py +0 -109
  44. omlish/formats/json/_antlr/JsonListener.py +0 -61
  45. omlish/formats/json/_antlr/JsonParser.py +0 -457
  46. omlish/formats/json/_antlr/JsonVisitor.py +0 -42
  47. omlish/io/trampoline.py +0 -289
  48. omlish/logs/abc.py +0 -319
  49. omlish/logs/color.py +0 -27
  50. omlish/logs/configs.py +0 -29
  51. omlish/logs/protocol.py +0 -218
  52. omlish/logs/timing.py +0 -58
  53. omlish/specs/irc/__init__.py +0 -0
  54. omlish/specs/irc/messages/__init__.py +0 -0
  55. omlish/specs/irc/messages/base.py +0 -49
  56. omlish/specs/irc/messages/formats.py +0 -92
  57. omlish/specs/irc/messages/messages.py +0 -774
  58. omlish/specs/irc/messages/parsing.py +0 -98
  59. omlish/specs/irc/numerics/__init__.py +0 -0
  60. omlish/specs/irc/numerics/formats.py +0 -97
  61. omlish/specs/irc/numerics/numerics.py +0 -865
  62. omlish/specs/irc/numerics/types.py +0 -59
  63. omlish/specs/irc/protocol/LICENSE +0 -11
  64. omlish/specs/irc/protocol/__init__.py +0 -61
  65. omlish/specs/irc/protocol/consts.py +0 -6
  66. omlish/specs/irc/protocol/errors.py +0 -30
  67. omlish/specs/irc/protocol/message.py +0 -21
  68. omlish/specs/irc/protocol/nuh.py +0 -55
  69. omlish/specs/irc/protocol/parsing.py +0 -158
  70. omlish/specs/irc/protocol/rendering.py +0 -153
  71. omlish/specs/irc/protocol/tags.py +0 -102
  72. omlish/specs/irc/protocol/utils.py +0 -30
  73. omlish/specs/proto/Protobuf3.g4 +0 -396
  74. omlish/specs/proto/__init__.py +0 -0
  75. omlish/specs/proto/_antlr/Protobuf3Lexer.py +0 -340
  76. omlish/specs/proto/_antlr/Protobuf3Listener.py +0 -448
  77. omlish/specs/proto/_antlr/Protobuf3Parser.py +0 -3909
  78. omlish/specs/proto/_antlr/Protobuf3Visitor.py +0 -257
  79. omlish/specs/proto/_antlr/__init__.py +0 -0
  80. omlish/specs/proto/nodes.py +0 -54
  81. omlish/specs/proto/parsing.py +0 -97
  82. omlish/sql/parsing/Minisql.g4 +0 -292
  83. omlish/sql/parsing/__init__.py +0 -0
  84. omlish/sql/parsing/_antlr/MinisqlLexer.py +0 -322
  85. omlish/sql/parsing/_antlr/MinisqlListener.py +0 -511
  86. omlish/sql/parsing/_antlr/MinisqlParser.py +0 -3763
  87. omlish/sql/parsing/_antlr/MinisqlVisitor.py +0 -292
  88. omlish/sql/parsing/_antlr/__init__.py +0 -0
  89. omlish/sql/parsing/parsing.py +0 -119
  90. /omlish/{.manifests.json → .omlish-manifests.json} +0 -0
  91. /omlish/{formats/json/_antlr → logs/std}/__init__.py +0 -0
  92. /omlish/logs/{noisy.py → std/noisy.py} +0 -0
  93. {omlish-0.0.0.dev424.dist-info → omlish-0.0.0.dev425.dist-info}/WHEEL +0 -0
  94. {omlish-0.0.0.dev424.dist-info → omlish-0.0.0.dev425.dist-info}/entry_points.txt +0 -0
  95. {omlish-0.0.0.dev424.dist-info → omlish-0.0.0.dev425.dist-info}/licenses/LICENSE +0 -0
  96. {omlish-0.0.0.dev424.dist-info → omlish-0.0.0.dev425.dist-info}/top_level.txt +0 -0
omlish/__about__.py CHANGED
@@ -1,5 +1,5 @@
1
- __version__ = '0.0.0.dev424'
2
- __revision__ = '74da5ba6eafb03e4fbf36459215eaf1864903ee2'
1
+ __version__ = '0.0.0.dev425'
2
+ __revision__ = '92376f181ba36a2d1eda16643d70fd1077e309f1'
3
3
 
4
4
 
5
5
  #
@@ -175,7 +175,7 @@ class SetuptoolsBase:
175
175
  '*.g4',
176
176
  '*.h',
177
177
 
178
- '.manifests.json',
178
+ '.omlish-manifests.json',
179
179
 
180
180
  'LICENSE',
181
181
  'LICENSE.txt',
@@ -24,7 +24,8 @@ def init_package(
24
24
  *,
25
25
  codegen: bool = False,
26
26
  ) -> None:
27
- pass
27
+ if init_globals['__name__'] != init_globals['__package__']:
28
+ raise NameError('Must call dataclasses.init_package from __init__')
28
29
 
29
30
 
30
31
  ##
@@ -117,9 +117,11 @@ class JsonStreamLexer(GenMachine[str, Token]):
117
117
  *,
118
118
  include_raw: bool = False,
119
119
  include_space: bool = False,
120
+ allow_comments: bool = False,
120
121
  ) -> None:
121
122
  self._include_raw = include_raw
122
123
  self._include_space = include_space
124
+ self._allow_comments = allow_comments
123
125
 
124
126
  self._ofs = 0
125
127
  self._line = 1
@@ -200,6 +202,9 @@ class JsonStreamLexer(GenMachine[str, Token]):
200
202
  if c in 'tfnIN':
201
203
  return self._do_const(c)
202
204
 
205
+ if self._allow_comments and c == '/':
206
+ return self._do_comment()
207
+
203
208
  self._raise(f'Unexpected character: {c}')
204
209
 
205
210
  def _do_string(self):
@@ -321,3 +326,6 @@ class JsonStreamLexer(GenMachine[str, Token]):
321
326
  yield self._make_tok(tk, tv, raw, pos)
322
327
 
323
328
  return self._do_main()
329
+
330
+ def _do_comment(self):
331
+ raise NotImplementedError
@@ -15,6 +15,8 @@ class JsonStreamValueParser(lang.ExitStacked):
15
15
  include_raw: bool = False
16
16
  yield_object_lists: bool = False
17
17
 
18
+ json5: bool = False
19
+
18
20
  #
19
21
 
20
22
  _lex: JsonStreamLexer = dc.field(init=False)
@@ -24,6 +26,7 @@ class JsonStreamValueParser(lang.ExitStacked):
24
26
  def _enter_contexts(self) -> None:
25
27
  self._lex = JsonStreamLexer(
26
28
  include_raw=self.include_raw,
29
+ allow_comments=self.json5,
27
30
  )
28
31
 
29
32
  self._parse = JsonStreamParser()
@@ -0,0 +1,22 @@
1
+ """
2
+ TODO:
3
+
4
+ Objects:
5
+ - Object keys may be an ECMAScript 5.1 IdentifierName.
6
+ - Objects may have a single trailing comma.
7
+ Arrays:
8
+ - Arrays may have a single trailing comma.
9
+ Strings:
10
+ - Strings may be single quoted.
11
+ - Strings may span multiple lines by escaping new line characters.
12
+ - Strings may include character escapes.
13
+ Numbers:
14
+ - Numbers may be hexadecimal.
15
+ - Numbers may have a leading or trailing decimal point.
16
+ - Numbers may be IEEE 754 positive infinity, negative infinity, and NaN.
17
+ - Numbers may begin with an explicit plus sign.
18
+ Comments:
19
+ - Single and multi-line comments are allowed.
20
+ White Space:
21
+ - Additional white space characters are allowed.
22
+ """
omlish/lang/__init__.py CHANGED
@@ -9,6 +9,8 @@ with _auto_proxy_init(
9
9
  ##
10
10
 
11
11
  from .asyncs import ( # noqa
12
+ as_async,
13
+
12
14
  async_list,
13
15
 
14
16
  sync_await,
@@ -216,7 +218,6 @@ with _auto_proxy_init(
216
218
 
217
219
  from .functions import ( # noqa
218
220
  VoidError,
219
- as_async,
220
221
  call_with,
221
222
  coalesce,
222
223
  cond_kw,
@@ -306,6 +307,7 @@ with _auto_proxy_init(
306
307
  )
307
308
 
308
309
  from .lazyglobals import ( # noqa
310
+ AmbiguousLazyGlobalsFallbackError,
309
311
  LazyGlobals,
310
312
  )
311
313
 
omlish/lang/asyncs.py CHANGED
@@ -1,7 +1,19 @@
1
+ import functools
1
2
  import typing as ta
2
3
 
3
4
 
4
5
  T = ta.TypeVar('T')
6
+ P = ta.ParamSpec('P')
7
+
8
+
9
+ ##
10
+
11
+
12
+ def as_async(fn: ta.Callable[P, T], *, wrap: bool = False) -> ta.Callable[P, ta.Awaitable[T]]:
13
+ async def inner(*args, **kwargs):
14
+ return fn(*args, **kwargs)
15
+
16
+ return functools.wraps(fn)(inner) if wrap else inner
5
17
 
6
18
 
7
19
  ##
omlish/lang/functions.py CHANGED
@@ -167,17 +167,6 @@ def void(*args: ta.Any, **kwargs: ta.Any) -> ta.NoReturn:
167
167
  ##
168
168
 
169
169
 
170
- def as_async(fn: ta.Callable[P, T]) -> ta.Callable[P, ta.Awaitable[T]]:
171
- @functools.wraps(fn)
172
- async def inner(*args, **kwargs):
173
- return fn(*args, **kwargs)
174
-
175
- return inner
176
-
177
-
178
- ##
179
-
180
-
181
170
  _MISSING = object()
182
171
 
183
172
 
@@ -4,6 +4,17 @@ import typing as ta
4
4
  ##
5
5
 
6
6
 
7
+ class AmbiguousLazyGlobalsFallbackError(Exception):
8
+ def __init__(self, attr: str, fallbacks: list[ta.Callable[[str], ta.Any]]) -> None:
9
+ super().__init__()
10
+
11
+ self.attr = attr
12
+ self.fallbacks = fallbacks
13
+
14
+ def __repr__(self) -> str:
15
+ return f'{self.__class__.__name__}({self.attr!r}, {self.fallbacks!r})'
16
+
17
+
7
18
  class LazyGlobals:
8
19
  def __init__(
9
20
  self,
@@ -17,6 +28,7 @@ class LazyGlobals:
17
28
  self._update_globals = update_globals
18
29
 
19
30
  self._attr_fns: dict[str, ta.Callable[[], ta.Any]] = {}
31
+ self._fallback_fns: list[ta.Callable[[str], ta.Callable[[], ta.Any]]] = []
20
32
 
21
33
  @classmethod
22
34
  def install(cls, globals: ta.MutableMapping[str, ta.Any]) -> 'LazyGlobals': # noqa
@@ -42,13 +54,23 @@ class LazyGlobals:
42
54
  self._attr_fns[attr] = fn
43
55
  return self
44
56
 
57
+ def add_fallback_fn(self, fn: ta.Callable[[str], ta.Callable[[], ta.Any]]) -> 'LazyGlobals':
58
+ self._fallback_fns.append(fn)
59
+ return self
60
+
45
61
  def get(self, attr: str) -> ta.Any:
46
- try:
47
- fn = self._attr_fns[attr]
48
- except KeyError:
49
- raise AttributeError(attr) from None
62
+ val: ta.Any
50
63
 
51
- val = fn()
64
+ if (attr_fn := self._attr_fns.get(attr)) is not None:
65
+ val = attr_fn()
66
+
67
+ elif (fallbacks := [(fb_fn, fb_fn(attr)) for fb_fn in self._fallback_fns]):
68
+ if len(fallbacks) > 1:
69
+ raise AmbiguousLazyGlobalsFallbackError(attr, [fb_fn for fb_fn, _ in fallbacks])
70
+ [val] = fallbacks
71
+
72
+ else:
73
+ raise AttributeError(attr)
52
74
 
53
75
  if self._update_globals and self._globals is not None:
54
76
  self._globals[attr] = val
omlish/lang/maysync.py CHANGED
@@ -3,7 +3,7 @@ import typing as ta
3
3
  from ..lite.maysync import MaysyncFn
4
4
  from ..lite.maysync import MaysyncGeneratorFn
5
5
  from ..lite.maysync import make_maysync as _make_maysync
6
- from .functions import as_async
6
+ from .asyncs import as_async
7
7
 
8
8
 
9
9
  T = ta.TypeVar('T')
@@ -68,5 +68,5 @@ def make_maysync_from_sync(
68
68
  ) -> ta.Callable[P, ta.Awaitable[T]]:
69
69
  return _make_maysync(
70
70
  s,
71
- a if a is not None else as_async(s),
71
+ a if a is not None else as_async(s, wrap=True),
72
72
  )
@@ -2,7 +2,6 @@ import types
2
2
  import typing as ta
3
3
 
4
4
  from .. import dataclasses as dc
5
- from .. import defs
6
5
  from .. import lang
7
6
  from .base import Lifecycle
8
7
  from .controller import LifecycleController
@@ -37,7 +36,7 @@ class LifecycleContextManager(ta.Generic[LifecycleT]):
37
36
  self._lifecycle = lifecycle
38
37
  self._controller = lifecycle if isinstance(lifecycle, LifecycleController) else LifecycleController(lifecycle)
39
38
 
40
- defs.repr('lifecycle', 'state')
39
+ __repr__ = lang.AttrRepr(['lifecycle', 'state'])
41
40
 
42
41
  @property
43
42
  def lifecycle(self) -> LifecycleT:
@@ -2,7 +2,6 @@ import abc
2
2
  import typing as ta
3
3
 
4
4
  from .. import check
5
- from .. import defs
6
5
  from .. import lang
7
6
  from .base import AnyLifecycle # noqa
8
7
  from .base import Lifecycle # noqa
@@ -48,7 +47,7 @@ class AnyLifecycleController(AnyLifecycle[R], lang.Abstract, ta.Generic[AnyLifec
48
47
  self._state = LifecycleStates.NEW
49
48
  self._listeners: list[AnyLifecycleListener[AnyLifecycleT, R]] = []
50
49
 
51
- defs.repr('lifecycle', 'state')
50
+ __repr__ = lang.AttrRepr(['lifecycle', 'state'])
52
51
 
53
52
  @property
54
53
  def lifecycle(self) -> AnyLifecycleT:
omlish/lite/asyncs.py ADDED
@@ -0,0 +1,15 @@
1
+ import functools
2
+ import typing as ta
3
+
4
+
5
+ T = ta.TypeVar('T')
6
+
7
+
8
+ ##
9
+
10
+
11
+ def as_async(fn: ta.Callable[..., T], *, wrap: bool = False) -> ta.Callable[..., ta.Awaitable[T]]:
12
+ async def inner(*args, **kwargs):
13
+ return fn(*args, **kwargs)
14
+
15
+ return functools.wraps(fn)(inner) if wrap else inner
omlish/lite/timing.py CHANGED
@@ -1,5 +1,5 @@
1
- from ..logs.timing import LogTimingContext
2
- from ..logs.timing import log_timing_context
1
+ from ..logs.utils import LogTimingContext
2
+ from ..logs.utils import log_timing_context
3
3
  from .logs import log
4
4
 
5
5
 
omlish/logs/all.py CHANGED
@@ -5,64 +5,53 @@ from .. import lang as _lang
5
5
  with _lang.auto_proxy_init(globals()):
6
6
  ##
7
7
 
8
- from .callers import ( # noqa
9
- LoggingCaller,
10
- )
11
-
12
- from .color import ( # noqa
13
- ColorLogFormatter,
8
+ from .std.filters import ( # noqa
9
+ TidLoggingFilter,
14
10
  )
15
11
 
16
- from .filters import ( # noqa
17
- TidLogFilter,
12
+ from .std.handlers import ( # noqa
13
+ ListLoggingHandler,
18
14
  )
19
15
 
20
- from .handlers import ( # noqa
21
- ListHandler,
16
+ from .std.json import ( # noqa
17
+ JsonLoggingFormatter,
22
18
  )
23
19
 
24
- from .json import ( # noqa
25
- JsonLogFormatter,
20
+ from .std.noisy import ( # noqa
21
+ silence_noisy_loggers,
26
22
  )
27
23
 
28
- from .levels import ( # noqa
29
- LogLevel,
24
+ from .std.proxy import ( # noqa
25
+ ProxyLoggingFilterer,
26
+ ProxyLoggingHandler,
30
27
  )
31
28
 
32
- from .noisy import ( # noqa
33
- silence_noisy_loggers,
29
+ from .callers import ( # noqa
30
+ LoggingCaller,
34
31
  )
35
32
 
36
- from .protocol import ( # noqa
37
- AnyLogging,
38
- Logging,
39
- AsyncLogging,
40
-
41
- AnyAbstractLogging,
42
- AbstractLogging,
43
- AbstractAsyncLogging,
44
-
45
- AnyNopLogging,
46
- NopLogging,
47
- NopAsyncLogging,
33
+ from .levels import ( # noqa
34
+ LogLevel,
48
35
 
49
- StdlibLogging,
36
+ NamedLogLevel,
50
37
  )
51
38
 
52
- from .proxy import ( # noqa
53
- ProxyLogFilterer,
54
- ProxyLogHandler,
39
+ from .protocols import ( # noqa
40
+ LoggerLike,
55
41
  )
56
42
 
57
43
  from .standard import ( # noqa
58
44
  STANDARD_LOG_FORMAT_PARTS,
59
- StandardLogFormatter,
45
+ StandardLoggingFormatter,
60
46
 
61
- StandardConfiguredLogHandler,
47
+ StandardConfiguredLoggingHandler,
62
48
 
63
49
  configure_standard_logging,
64
50
  )
65
51
 
66
52
  from .utils import ( # noqa
53
+ LogTimingContext,
54
+ log_timing_context,
55
+
67
56
  error_logging,
68
57
  )
omlish/logs/base.py ADDED
@@ -0,0 +1,248 @@
1
+ # ruff: noqa: UP006 UP007 UP045 UP046
2
+ # @omlish-lite
3
+ import abc
4
+ import sys
5
+ import time
6
+ import types
7
+ import typing as ta
8
+
9
+ 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
16
+ from .levels import NamedLogLevel
17
+ from .times import LoggingTimeFields
18
+
19
+
20
+ T = ta.TypeVar('T')
21
+
22
+
23
+ LogLevel = int # ta.TypeAlias
24
+
25
+ LoggingExcInfoTuple = ta.Tuple[ta.Type[BaseException], BaseException, ta.Optional[types.TracebackType]] # ta.TypeAlias
26
+ LoggingExcInfo = ta.Union[BaseException, LoggingExcInfoTuple] # ta.TypeAlias
27
+ LoggingExcInfoArg = ta.Union[LoggingExcInfo, bool, None] # ta.TypeAlias
28
+
29
+
30
+ ##
31
+
32
+
33
+ @ta.final
34
+ class LoggingContext:
35
+ level: NamedLogLevel
36
+
37
+ time_ns: int
38
+
39
+ exc_info: ta.Optional[LoggingExcInfo] = None
40
+ exc_info_tuple: ta.Optional[LoggingExcInfoTuple] = None
41
+
42
+ @ta.final
43
+ class NOT_SET: # noqa
44
+ def __new__(cls, *args, **kwargs): # noqa
45
+ raise TypeError
46
+
47
+ #
48
+
49
+ def __init__(
50
+ self,
51
+ level: LogLevel,
52
+ *,
53
+ time_ns: ta.Optional[int] = None,
54
+
55
+ exc_info: LoggingExcInfoArg = False,
56
+
57
+ caller: ta.Union[LoggingCaller, ta.Type[NOT_SET], None] = NOT_SET,
58
+ stack_offset: int = 0,
59
+ stack_info: bool = False,
60
+ ) -> None:
61
+ self.level = level if level.__class__ is NamedLogLevel else NamedLogLevel(level) # type: ignore[assignment]
62
+
63
+ #
64
+
65
+ if time_ns is None:
66
+ time_ns = time.time_ns()
67
+ self.time_ns: int = time_ns
68
+
69
+ #
70
+
71
+ if exc_info is True:
72
+ sys_exc_info = sys.exc_info()
73
+ if sys_exc_info[0] is not None:
74
+ exc_info = sys_exc_info
75
+ else:
76
+ exc_info = None
77
+ elif exc_info is False:
78
+ exc_info = None
79
+
80
+ if exc_info is not None:
81
+ self.exc_info = exc_info
82
+ if isinstance(exc_info, BaseException):
83
+ self.exc_info_tuple = (type(exc_info), exc_info, exc_info.__traceback__)
84
+ else:
85
+ self.exc_info_tuple = exc_info
86
+
87
+ #
88
+
89
+ if caller is not LoggingContext.NOT_SET:
90
+ self._caller = caller # type: ignore[assignment]
91
+ else:
92
+ self._stack_offset = stack_offset
93
+ self._stack_info = stack_info
94
+
95
+ #
96
+
97
+ self.thread = LoggingThreadInfo.build()
98
+ self.process = LoggingProcessInfo.build()
99
+ self.multiprocessing = LoggingMultiprocessingInfo.build()
100
+ self.asyncio_task = LoggingAsyncioTaskInfo.build()
101
+
102
+ #
103
+
104
+ _times: LoggingTimeFields
105
+
106
+ @property
107
+ def times(self) -> LoggingTimeFields:
108
+ try:
109
+ return self._times
110
+ except AttributeError:
111
+ pass
112
+
113
+ times = self._times = LoggingTimeFields.build(self.time_ns)
114
+ return times
115
+
116
+ #
117
+
118
+ def inc_stack_offset(self, ofs: int = 1) -> 'LoggingContext':
119
+ if hasattr(self, '_stack_offset'):
120
+ self._stack_offset += ofs
121
+ return self
122
+
123
+ _caller: ta.Optional[LoggingCaller]
124
+
125
+ def build_caller(self) -> ta.Optional[LoggingCaller]:
126
+ """Must be cooperatively called only from the exact configured _stack_offset."""
127
+
128
+ try:
129
+ return self._caller
130
+ except AttributeError:
131
+ pass
132
+
133
+ caller = self._caller = LoggingCaller.find(
134
+ self._stack_offset + 1,
135
+ stack_info=self._stack_info,
136
+ )
137
+ return caller
138
+
139
+ def caller(self) -> ta.Optional[LoggingCaller]:
140
+ try:
141
+ return self._caller
142
+ except AttributeError:
143
+ return None
144
+
145
+ _source_file: ta.Optional[LoggingSourceFileInfo]
146
+
147
+ def source_file(self) -> ta.Optional[LoggingSourceFileInfo]:
148
+ try:
149
+ return self._source_file
150
+ except AttributeError:
151
+ pass
152
+
153
+ if (caller := self.caller()) is None:
154
+ return None
155
+
156
+ src_file = self._source_file = LoggingSourceFileInfo.build(caller.file_path)
157
+ return src_file
158
+
159
+
160
+ ##
161
+
162
+
163
+ class AnyLogger(Abstract, ta.Generic[T]):
164
+ def is_enabled_for(self, level: LogLevel) -> bool:
165
+ return self.get_effective_level() >= level
166
+
167
+ @abc.abstractmethod
168
+ def get_effective_level(self) -> LogLevel:
169
+ raise NotImplementedError
170
+
171
+ #
172
+
173
+ @ta.final
174
+ def isEnabledFor(self, level: LogLevel) -> bool: # noqa
175
+ return self.is_enabled_for(level)
176
+
177
+ @ta.final
178
+ def getEffectiveLevel(self) -> LogLevel: # noqa
179
+ return self.get_effective_level()
180
+
181
+ #
182
+
183
+ @ta.final
184
+ def debug(self, msg: str, *args: ta.Any, **kwargs: ta.Any) -> T:
185
+ return self._log(LoggingContext(NamedLogLevel.DEBUG, stack_offset=1), msg, *args, **kwargs)
186
+
187
+ @ta.final
188
+ def info(self, msg: str, *args: ta.Any, **kwargs: ta.Any) -> T:
189
+ return self._log(LoggingContext(NamedLogLevel.INFO, stack_offset=1), msg, *args, **kwargs)
190
+
191
+ @ta.final
192
+ def warning(self, msg: str, *args: ta.Any, **kwargs: ta.Any) -> T:
193
+ return self._log(LoggingContext(NamedLogLevel.WARNING, stack_offset=1), msg, *args, **kwargs)
194
+
195
+ @ta.final
196
+ def error(self, msg: str, *args: ta.Any, **kwargs: ta.Any) -> T:
197
+ return self._log(LoggingContext(NamedLogLevel.ERROR, stack_offset=1), msg, *args, **kwargs)
198
+
199
+ @ta.final
200
+ def exception(self, msg: str, *args: ta.Any, exc_info: LoggingExcInfoArg = True, **kwargs: ta.Any) -> T:
201
+ return self._log(LoggingContext(NamedLogLevel.ERROR, exc_info=exc_info, stack_offset=1), msg, *args, **kwargs)
202
+
203
+ @ta.final
204
+ def critical(self, msg: str, *args: ta.Any, **kwargs: ta.Any) -> T:
205
+ return self._log(LoggingContext(NamedLogLevel.CRITICAL, stack_offset=1), msg, *args, **kwargs)
206
+
207
+ @ta.final
208
+ def log(self, level: LogLevel, msg: str, *args: ta.Any, **kwargs: ta.Any) -> T:
209
+ return self._log(LoggingContext(level, stack_offset=1), msg, *args, **kwargs)
210
+
211
+ #
212
+
213
+ @abc.abstractmethod
214
+ def _log(self, ctx: LoggingContext, msg: str, *args: ta.Any, **kwargs: ta.Any) -> T:
215
+ raise NotImplementedError
216
+
217
+
218
+ class Logger(AnyLogger[None], Abstract):
219
+ @abc.abstractmethod
220
+ def _log(self, ctx: LoggingContext, msg: str, *args: ta.Any, **kwargs: ta.Any) -> None:
221
+ raise NotImplementedError
222
+
223
+
224
+ class AsyncLogger(AnyLogger[ta.Awaitable[None]], Abstract):
225
+ @abc.abstractmethod
226
+ def _log(self, ctx: LoggingContext, msg: str, *args: ta.Any, **kwargs: ta.Any) -> ta.Awaitable[None]:
227
+ raise NotImplementedError
228
+
229
+
230
+ ##
231
+
232
+
233
+ class AnyNopLogger(AnyLogger[T], Abstract):
234
+ @ta.final
235
+ def get_effective_level(self) -> LogLevel:
236
+ return 999
237
+
238
+
239
+ @ta.final
240
+ class NopLogger(AnyNopLogger[None], Logger):
241
+ def _log(self, ctx: LoggingContext, msg: str, *args: ta.Any, **kwargs: ta.Any) -> None:
242
+ pass
243
+
244
+
245
+ @ta.final
246
+ class AsyncNopLogger(AnyNopLogger[ta.Awaitable[None]], AsyncLogger):
247
+ async def _log(self, ctx: LoggingContext, msg: str, *args: ta.Any, **kwargs: ta.Any) -> None:
248
+ pass