omdev 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.
- omdev/scripts/ci.py +1016 -719
- omdev/scripts/interp.py +47 -13
- omdev/scripts/pyproject.py +999 -702
- {omdev-0.0.0.dev429.dist-info → omdev-0.0.0.dev431.dist-info}/METADATA +2 -2
- {omdev-0.0.0.dev429.dist-info → omdev-0.0.0.dev431.dist-info}/RECORD +9 -9
- {omdev-0.0.0.dev429.dist-info → omdev-0.0.0.dev431.dist-info}/WHEEL +0 -0
- {omdev-0.0.0.dev429.dist-info → omdev-0.0.0.dev431.dist-info}/entry_points.txt +0 -0
- {omdev-0.0.0.dev429.dist-info → omdev-0.0.0.dev431.dist-info}/licenses/LICENSE +0 -0
- {omdev-0.0.0.dev429.dist-info → omdev-0.0.0.dev431.dist-info}/top_level.txt +0 -0
omdev/scripts/pyproject.py
CHANGED
@@ -130,6 +130,13 @@ U = ta.TypeVar('U')
|
|
130
130
|
# ../../omlish/lite/timeouts.py
|
131
131
|
TimeoutLike = ta.Union['Timeout', ta.Type['Timeout.DEFAULT'], ta.Iterable['TimeoutLike'], float, None] # ta.TypeAlias
|
132
132
|
|
133
|
+
# ../../omlish/logs/infos.py
|
134
|
+
LoggingMsgFn = ta.Callable[[], ta.Union[str, tuple]] # ta.TypeAlias
|
135
|
+
LoggingExcInfoTuple = ta.Tuple[ta.Type[BaseException], BaseException, ta.Optional[types.TracebackType]] # ta.TypeAlias
|
136
|
+
LoggingExcInfo = ta.Union[BaseException, LoggingExcInfoTuple] # ta.TypeAlias
|
137
|
+
LoggingExcInfoArg = ta.Union[LoggingExcInfo, bool, None] # ta.TypeAlias
|
138
|
+
LoggingContextInfo = ta.Any # ta.TypeAlias
|
139
|
+
|
133
140
|
# ../../omlish/asyncs/asyncio/timeouts.py
|
134
141
|
AwaitableT = ta.TypeVar('AwaitableT', bound=ta.Awaitable)
|
135
142
|
|
@@ -140,12 +147,7 @@ InjectorProviderFnMap = ta.Mapping['InjectorKey', 'InjectorProviderFn']
|
|
140
147
|
InjectorBindingOrBindings = ta.Union['InjectorBinding', 'InjectorBindings']
|
141
148
|
|
142
149
|
# ../../omlish/logs/contexts.py
|
143
|
-
|
144
|
-
LoggingExcInfo = ta.Union[BaseException, LoggingExcInfoTuple] # ta.TypeAlias
|
145
|
-
LoggingExcInfoArg = ta.Union[LoggingExcInfo, bool, None] # ta.TypeAlias
|
146
|
-
|
147
|
-
# ../../omlish/logs/base.py
|
148
|
-
LoggingMsgFn = ta.Callable[[], ta.Union[str, tuple]] # ta.TypeAlias
|
150
|
+
LoggingContextInfoT = ta.TypeVar('LoggingContextInfoT', bound=LoggingContextInfo)
|
149
151
|
|
150
152
|
# ../../omlish/subprocesses/base.py
|
151
153
|
SubprocessChannelOption = ta.Literal['pipe', 'stdout', 'devnull'] # ta.TypeAlias
|
@@ -2959,124 +2961,6 @@ def typing_annotations_attr() -> str:
|
|
2959
2961
|
return _TYPING_ANNOTATIONS_ATTR
|
2960
2962
|
|
2961
2963
|
|
2962
|
-
########################################
|
2963
|
-
# ../../../omlish/logs/infos.py
|
2964
|
-
|
2965
|
-
|
2966
|
-
##
|
2967
|
-
|
2968
|
-
|
2969
|
-
def logging_context_info(cls):
|
2970
|
-
return cls
|
2971
|
-
|
2972
|
-
|
2973
|
-
##
|
2974
|
-
|
2975
|
-
|
2976
|
-
@logging_context_info
|
2977
|
-
@ta.final
|
2978
|
-
class LoggingSourceFileInfo(ta.NamedTuple):
|
2979
|
-
file_name: str
|
2980
|
-
module: str
|
2981
|
-
|
2982
|
-
@classmethod
|
2983
|
-
def build(cls, file_path: ta.Optional[str]) -> ta.Optional['LoggingSourceFileInfo']:
|
2984
|
-
if file_path is None:
|
2985
|
-
return None
|
2986
|
-
|
2987
|
-
# https://github.com/python/cpython/blob/e709361fc87d0d9ab9c58033a0a7f2fef0ad43d2/Lib/logging/__init__.py#L331-L336 # noqa
|
2988
|
-
try:
|
2989
|
-
file_name = os.path.basename(file_path)
|
2990
|
-
module = os.path.splitext(file_name)[0]
|
2991
|
-
except (TypeError, ValueError, AttributeError):
|
2992
|
-
return None
|
2993
|
-
|
2994
|
-
return cls(
|
2995
|
-
file_name,
|
2996
|
-
module,
|
2997
|
-
)
|
2998
|
-
|
2999
|
-
|
3000
|
-
##
|
3001
|
-
|
3002
|
-
|
3003
|
-
@logging_context_info
|
3004
|
-
@ta.final
|
3005
|
-
class LoggingThreadInfo(ta.NamedTuple):
|
3006
|
-
ident: int
|
3007
|
-
native_id: ta.Optional[int]
|
3008
|
-
name: str
|
3009
|
-
|
3010
|
-
@classmethod
|
3011
|
-
def build(cls) -> 'LoggingThreadInfo':
|
3012
|
-
return cls(
|
3013
|
-
threading.get_ident(),
|
3014
|
-
threading.get_native_id() if hasattr(threading, 'get_native_id') else None,
|
3015
|
-
threading.current_thread().name,
|
3016
|
-
)
|
3017
|
-
|
3018
|
-
|
3019
|
-
##
|
3020
|
-
|
3021
|
-
|
3022
|
-
@logging_context_info
|
3023
|
-
@ta.final
|
3024
|
-
class LoggingProcessInfo(ta.NamedTuple):
|
3025
|
-
pid: int
|
3026
|
-
|
3027
|
-
@classmethod
|
3028
|
-
def build(cls) -> 'LoggingProcessInfo':
|
3029
|
-
return cls(
|
3030
|
-
os.getpid(),
|
3031
|
-
)
|
3032
|
-
|
3033
|
-
|
3034
|
-
##
|
3035
|
-
|
3036
|
-
|
3037
|
-
@logging_context_info
|
3038
|
-
@ta.final
|
3039
|
-
class LoggingMultiprocessingInfo(ta.NamedTuple):
|
3040
|
-
process_name: str
|
3041
|
-
|
3042
|
-
@classmethod
|
3043
|
-
def build(cls) -> ta.Optional['LoggingMultiprocessingInfo']:
|
3044
|
-
# https://github.com/python/cpython/blob/e709361fc87d0d9ab9c58033a0a7f2fef0ad43d2/Lib/logging/__init__.py#L355-L364 # noqa
|
3045
|
-
if (mp := sys.modules.get('multiprocessing')) is None:
|
3046
|
-
return None
|
3047
|
-
|
3048
|
-
return cls(
|
3049
|
-
mp.current_process().name,
|
3050
|
-
)
|
3051
|
-
|
3052
|
-
|
3053
|
-
##
|
3054
|
-
|
3055
|
-
|
3056
|
-
@logging_context_info
|
3057
|
-
@ta.final
|
3058
|
-
class LoggingAsyncioTaskInfo(ta.NamedTuple):
|
3059
|
-
name: str
|
3060
|
-
|
3061
|
-
@classmethod
|
3062
|
-
def build(cls) -> ta.Optional['LoggingAsyncioTaskInfo']:
|
3063
|
-
# https://github.com/python/cpython/blob/e709361fc87d0d9ab9c58033a0a7f2fef0ad43d2/Lib/logging/__init__.py#L372-L377 # noqa
|
3064
|
-
if (asyncio := sys.modules.get('asyncio')) is None:
|
3065
|
-
return None
|
3066
|
-
|
3067
|
-
try:
|
3068
|
-
task = asyncio.current_task()
|
3069
|
-
except Exception: # noqa
|
3070
|
-
return None
|
3071
|
-
|
3072
|
-
if task is None:
|
3073
|
-
return None
|
3074
|
-
|
3075
|
-
return cls(
|
3076
|
-
task.get_name(), # Always non-None
|
3077
|
-
)
|
3078
|
-
|
3079
|
-
|
3080
2964
|
########################################
|
3081
2965
|
# ../../../omlish/logs/levels.py
|
3082
2966
|
|
@@ -3096,36 +2980,66 @@ class NamedLogLevel(int):
|
|
3096
2980
|
|
3097
2981
|
#
|
3098
2982
|
|
3099
|
-
|
3100
|
-
|
3101
|
-
|
2983
|
+
_CACHE: ta.ClassVar[ta.MutableMapping[int, 'NamedLogLevel']] = {}
|
2984
|
+
|
2985
|
+
@ta.overload
|
2986
|
+
def __new__(cls, name: str, offset: int = 0, /) -> 'NamedLogLevel':
|
2987
|
+
...
|
2988
|
+
|
2989
|
+
@ta.overload
|
2990
|
+
def __new__(cls, i: int, /) -> 'NamedLogLevel':
|
2991
|
+
...
|
2992
|
+
|
2993
|
+
def __new__(cls, x, offset=0, /):
|
2994
|
+
if isinstance(x, str):
|
2995
|
+
return cls(cls._INTS_BY_NAME[x.upper()] + offset)
|
2996
|
+
elif not offset and (c := cls._CACHE.get(x)) is not None:
|
2997
|
+
return c
|
2998
|
+
else:
|
2999
|
+
return super().__new__(cls, x + offset)
|
3000
|
+
|
3001
|
+
#
|
3102
3002
|
|
3103
|
-
|
3003
|
+
_name_and_offset: ta.Tuple[str, int]
|
3104
3004
|
|
3105
3005
|
@property
|
3106
|
-
def
|
3006
|
+
def name_and_offset(self) -> ta.Tuple[str, int]:
|
3107
3007
|
try:
|
3108
|
-
return self.
|
3008
|
+
return self._name_and_offset
|
3109
3009
|
except AttributeError:
|
3110
3010
|
pass
|
3111
3011
|
|
3112
|
-
if (n := self.
|
3012
|
+
if (n := self._NAMES_BY_INT.get(self)) is not None:
|
3013
|
+
t = (n, 0)
|
3014
|
+
else:
|
3113
3015
|
for n, i in self._NAME_INT_PAIRS: # noqa
|
3114
3016
|
if self >= i:
|
3017
|
+
t = (n, (self - i))
|
3115
3018
|
break
|
3116
3019
|
else:
|
3117
|
-
|
3020
|
+
t = ('NOTSET', int(self))
|
3021
|
+
|
3022
|
+
self._name_and_offset = t
|
3023
|
+
return t
|
3024
|
+
|
3025
|
+
@property
|
3026
|
+
def exact_name(self) -> ta.Optional[str]:
|
3027
|
+
n, o = self.name_and_offset
|
3028
|
+
return n if not o else None
|
3118
3029
|
|
3119
|
-
|
3030
|
+
@property
|
3031
|
+
def effective_name(self) -> str:
|
3032
|
+
n, _ = self.name_and_offset
|
3120
3033
|
return n
|
3121
3034
|
|
3122
3035
|
#
|
3123
3036
|
|
3124
|
-
def __repr__(self) -> str:
|
3125
|
-
return f'{self.__class__.__name__}({int(self)})'
|
3126
|
-
|
3127
3037
|
def __str__(self) -> str:
|
3128
|
-
return self.exact_name or f'{self.effective_name
|
3038
|
+
return self.exact_name or f'{self.effective_name}{int(self):+}'
|
3039
|
+
|
3040
|
+
def __repr__(self) -> str:
|
3041
|
+
n, o = self.name_and_offset
|
3042
|
+
return f'{self.__class__.__name__}({n!r}{f", {int(o)}" if o else ""})'
|
3129
3043
|
|
3130
3044
|
#
|
3131
3045
|
|
@@ -3145,6 +3059,9 @@ NamedLogLevel.DEBUG = NamedLogLevel(logging.DEBUG)
|
|
3145
3059
|
NamedLogLevel.NOTSET = NamedLogLevel(logging.NOTSET)
|
3146
3060
|
|
3147
3061
|
|
3062
|
+
NamedLogLevel._CACHE.update({i: NamedLogLevel(i) for i in NamedLogLevel._NAMES_BY_INT}) # noqa
|
3063
|
+
|
3064
|
+
|
3148
3065
|
########################################
|
3149
3066
|
# ../../../omlish/logs/std/filters.py
|
3150
3067
|
|
@@ -5527,74 +5444,362 @@ class PredicateTimeout(Timeout):
|
|
5527
5444
|
|
5528
5445
|
|
5529
5446
|
########################################
|
5530
|
-
# ../../../omlish/logs/
|
5447
|
+
# ../../../omlish/logs/infos.py
|
5448
|
+
"""
|
5449
|
+
TODO:
|
5450
|
+
- remove redundant info fields only present for std adaptation (Level.name, ...)
|
5451
|
+
"""
|
5531
5452
|
|
5532
5453
|
|
5533
5454
|
##
|
5534
5455
|
|
5535
5456
|
|
5536
|
-
|
5457
|
+
def logging_context_info(cls):
|
5458
|
+
return cls
|
5459
|
+
|
5460
|
+
|
5537
5461
|
@ta.final
|
5538
|
-
class
|
5539
|
-
|
5540
|
-
|
5541
|
-
name: str
|
5542
|
-
stack_info: ta.Optional[str]
|
5462
|
+
class LoggingContextInfos:
|
5463
|
+
def __new__(cls, *args, **kwargs): # noqa
|
5464
|
+
raise TypeError
|
5543
5465
|
|
5544
|
-
|
5545
|
-
def is_internal_frame(cls, frame: types.FrameType) -> bool:
|
5546
|
-
file_path = os.path.normcase(frame.f_code.co_filename)
|
5466
|
+
#
|
5547
5467
|
|
5548
|
-
|
5549
|
-
|
5550
|
-
|
5551
|
-
|
5552
|
-
return True
|
5468
|
+
@logging_context_info
|
5469
|
+
@ta.final
|
5470
|
+
class Name(ta.NamedTuple):
|
5471
|
+
name: str
|
5553
5472
|
|
5554
|
-
|
5473
|
+
@logging_context_info
|
5474
|
+
@ta.final
|
5475
|
+
class Level(ta.NamedTuple):
|
5476
|
+
level: NamedLogLevel
|
5477
|
+
name: str
|
5555
5478
|
|
5556
|
-
|
5557
|
-
|
5558
|
-
|
5479
|
+
@classmethod
|
5480
|
+
def build(cls, level: int) -> 'LoggingContextInfos.Level':
|
5481
|
+
nl: NamedLogLevel = level if level.__class__ is NamedLogLevel else NamedLogLevel(level) # type: ignore[assignment] # noqa
|
5482
|
+
return cls(
|
5483
|
+
level=nl,
|
5484
|
+
name=logging.getLevelName(nl),
|
5485
|
+
)
|
5486
|
+
|
5487
|
+
@logging_context_info
|
5488
|
+
@ta.final
|
5489
|
+
class Msg(ta.NamedTuple):
|
5490
|
+
msg: str
|
5491
|
+
args: ta.Union[tuple, ta.Mapping[ta.Any, ta.Any], None]
|
5492
|
+
|
5493
|
+
@classmethod
|
5494
|
+
def build(
|
5495
|
+
cls,
|
5496
|
+
msg: ta.Union[str, tuple, LoggingMsgFn],
|
5497
|
+
*args: ta.Any,
|
5498
|
+
) -> 'LoggingContextInfos.Msg':
|
5499
|
+
s: str
|
5500
|
+
a: ta.Any
|
5501
|
+
|
5502
|
+
if callable(msg):
|
5503
|
+
if args:
|
5504
|
+
raise TypeError(f'Must not provide both a message function and args: {msg=} {args=}')
|
5505
|
+
x = msg()
|
5506
|
+
if isinstance(x, str):
|
5507
|
+
s, a = x, ()
|
5508
|
+
elif isinstance(x, tuple):
|
5509
|
+
if x:
|
5510
|
+
s, a = x[0], x[1:]
|
5511
|
+
else:
|
5512
|
+
s, a = '', ()
|
5513
|
+
else:
|
5514
|
+
raise TypeError(x)
|
5559
5515
|
|
5560
|
-
|
5561
|
-
|
5562
|
-
|
5563
|
-
|
5564
|
-
|
5516
|
+
elif isinstance(msg, tuple):
|
5517
|
+
if args:
|
5518
|
+
raise TypeError(f'Must not provide both a tuple message and args: {msg=} {args=}')
|
5519
|
+
if msg:
|
5520
|
+
s, a = msg[0], msg[1:]
|
5521
|
+
else:
|
5522
|
+
s, a = '', ()
|
5565
5523
|
|
5566
|
-
|
5524
|
+
elif isinstance(msg, str):
|
5525
|
+
s, a = msg, args
|
5567
5526
|
|
5568
|
-
|
5527
|
+
else:
|
5528
|
+
raise TypeError(msg)
|
5529
|
+
|
5530
|
+
# https://github.com/python/cpython/blob/e709361fc87d0d9ab9c58033a0a7f2fef0ad43d2/Lib/logging/__init__.py#L307 # noqa
|
5531
|
+
if a and len(a) == 1 and isinstance(a[0], collections.abc.Mapping) and a[0]:
|
5532
|
+
a = a[0]
|
5533
|
+
|
5534
|
+
return cls(
|
5535
|
+
msg=s,
|
5536
|
+
args=a,
|
5537
|
+
)
|
5538
|
+
|
5539
|
+
@logging_context_info
|
5540
|
+
@ta.final
|
5541
|
+
class Extra(ta.NamedTuple):
|
5542
|
+
extra: ta.Mapping[ta.Any, ta.Any]
|
5543
|
+
|
5544
|
+
@logging_context_info
|
5545
|
+
@ta.final
|
5546
|
+
class Time(ta.NamedTuple):
|
5547
|
+
ns: int
|
5548
|
+
secs: float
|
5549
|
+
msecs: float
|
5550
|
+
relative_secs: float
|
5551
|
+
|
5552
|
+
@classmethod
|
5553
|
+
def get_std_start_ns(cls) -> int:
|
5554
|
+
x: ta.Any = logging._startTime # type: ignore[attr-defined] # noqa
|
5555
|
+
|
5556
|
+
# Before 3.13.0b1 this will be `time.time()`, a float of seconds. After that, it will be `time.time_ns()`,
|
5557
|
+
# an int.
|
5558
|
+
#
|
5559
|
+
# See:
|
5560
|
+
# - https://github.com/python/cpython/commit/1316692e8c7c1e1f3b6639e51804f9db5ed892ea
|
5561
|
+
#
|
5562
|
+
if isinstance(x, float):
|
5563
|
+
return int(x * 1e9)
|
5564
|
+
else:
|
5565
|
+
return x
|
5566
|
+
|
5567
|
+
@classmethod
|
5568
|
+
def build(
|
5569
|
+
cls,
|
5570
|
+
ns: int,
|
5571
|
+
*,
|
5572
|
+
start_ns: ta.Optional[int] = None,
|
5573
|
+
) -> 'LoggingContextInfos.Time':
|
5574
|
+
# https://github.com/python/cpython/commit/1316692e8c7c1e1f3b6639e51804f9db5ed892ea
|
5575
|
+
secs = ns / 1e9 # ns to float seconds
|
5576
|
+
|
5577
|
+
# Get the number of whole milliseconds (0-999) in the fractional part of seconds.
|
5578
|
+
# Eg: 1_677_903_920_999_998_503 ns --> 999_998_503 ns--> 999 ms
|
5579
|
+
# Convert to float by adding 0.0 for historical reasons. See gh-89047
|
5580
|
+
msecs = (ns % 1_000_000_000) // 1_000_000 + 0.0
|
5581
|
+
|
5582
|
+
# https://github.com/python/cpython/commit/1500a23f33f5a6d052ff1ef6383d9839928b8ff1
|
5583
|
+
if msecs == 999.0 and int(secs) != ns // 1_000_000_000:
|
5584
|
+
# ns -> sec conversion can round up, e.g:
|
5585
|
+
# 1_677_903_920_999_999_900 ns --> 1_677_903_921.0 sec
|
5586
|
+
msecs = 0.0
|
5587
|
+
|
5588
|
+
if start_ns is None:
|
5589
|
+
start_ns = cls.get_std_start_ns()
|
5590
|
+
relative_secs = (ns - start_ns) / 1e6
|
5591
|
+
|
5592
|
+
return cls(
|
5593
|
+
ns=ns,
|
5594
|
+
secs=secs,
|
5595
|
+
msecs=msecs,
|
5596
|
+
relative_secs=relative_secs,
|
5597
|
+
)
|
5598
|
+
|
5599
|
+
@logging_context_info
|
5600
|
+
@ta.final
|
5601
|
+
class Exc(ta.NamedTuple):
|
5602
|
+
info: LoggingExcInfo
|
5603
|
+
info_tuple: LoggingExcInfoTuple
|
5604
|
+
|
5605
|
+
@classmethod
|
5606
|
+
def build(
|
5607
|
+
cls,
|
5608
|
+
arg: LoggingExcInfoArg = False,
|
5609
|
+
) -> ta.Optional['LoggingContextInfos.Exc']:
|
5610
|
+
if arg is True:
|
5611
|
+
sys_exc_info = sys.exc_info()
|
5612
|
+
if sys_exc_info[0] is not None:
|
5613
|
+
arg = sys_exc_info
|
5614
|
+
else:
|
5615
|
+
arg = None
|
5616
|
+
elif arg is False:
|
5617
|
+
arg = None
|
5618
|
+
if arg is None:
|
5619
|
+
return None
|
5620
|
+
|
5621
|
+
info: LoggingExcInfo = arg
|
5622
|
+
if isinstance(info, BaseException):
|
5623
|
+
info_tuple: LoggingExcInfoTuple = (type(info), info, info.__traceback__) # noqa
|
5624
|
+
else:
|
5625
|
+
info_tuple = info
|
5626
|
+
|
5627
|
+
return cls(
|
5628
|
+
info=info,
|
5629
|
+
info_tuple=info_tuple,
|
5630
|
+
)
|
5631
|
+
|
5632
|
+
@logging_context_info
|
5633
|
+
@ta.final
|
5634
|
+
class Caller(ta.NamedTuple):
|
5635
|
+
file_path: str
|
5636
|
+
line_no: int
|
5637
|
+
func_name: str
|
5638
|
+
stack_info: ta.Optional[str]
|
5639
|
+
|
5640
|
+
@classmethod
|
5641
|
+
def is_internal_frame(cls, frame: types.FrameType) -> bool:
|
5642
|
+
file_path = os.path.normcase(frame.f_code.co_filename)
|
5643
|
+
|
5644
|
+
# Yes, really.
|
5645
|
+
# https://github.com/python/cpython/blob/e709361fc87d0d9ab9c58033a0a7f2fef0ad43d2/Lib/logging/__init__.py#L204 # noqa
|
5646
|
+
# https://github.com/python/cpython/commit/5ca6d7469be53960843df39bb900e9c3359f127f
|
5647
|
+
if 'importlib' in file_path and '_bootstrap' in file_path:
|
5648
|
+
return True
|
5649
|
+
|
5650
|
+
return False
|
5651
|
+
|
5652
|
+
@classmethod
|
5653
|
+
def find_frame(cls, stack_offset: int = 0) -> ta.Optional[types.FrameType]:
|
5654
|
+
f: ta.Optional[types.FrameType] = sys._getframe(2 + stack_offset) # noqa
|
5655
|
+
|
5656
|
+
while f is not None:
|
5657
|
+
# NOTE: We don't check __file__ like stdlib since we may be running amalgamated - we rely on careful,
|
5658
|
+
# manual stack_offset management.
|
5659
|
+
if hasattr(f, 'f_code'):
|
5660
|
+
return f
|
5661
|
+
|
5662
|
+
f = f.f_back
|
5569
5663
|
|
5570
|
-
@classmethod
|
5571
|
-
def find(
|
5572
|
-
cls,
|
5573
|
-
ofs: int = 0,
|
5574
|
-
*,
|
5575
|
-
stack_info: bool = False,
|
5576
|
-
) -> ta.Optional['LoggingCaller']:
|
5577
|
-
if (f := cls.find_frame(ofs + 1)) is None:
|
5578
5664
|
return None
|
5579
5665
|
|
5580
|
-
|
5581
|
-
|
5582
|
-
|
5583
|
-
|
5584
|
-
|
5585
|
-
|
5586
|
-
|
5587
|
-
if
|
5588
|
-
|
5666
|
+
@classmethod
|
5667
|
+
def build(
|
5668
|
+
cls,
|
5669
|
+
stack_offset: int = 0,
|
5670
|
+
*,
|
5671
|
+
stack_info: bool = False,
|
5672
|
+
) -> ta.Optional['LoggingContextInfos.Caller']:
|
5673
|
+
if (f := cls.find_frame(stack_offset + 1)) is None:
|
5674
|
+
return None
|
5589
5675
|
|
5590
|
-
|
5591
|
-
|
5592
|
-
|
5593
|
-
|
5594
|
-
|
5676
|
+
# https://github.com/python/cpython/blob/08e9794517063c8cd92c48714071b1d3c60b71bd/Lib/logging/__init__.py#L1616-L1623 # noqa
|
5677
|
+
sinfo = None
|
5678
|
+
if stack_info:
|
5679
|
+
sio = io.StringIO()
|
5680
|
+
traceback.print_stack(f, file=sio)
|
5681
|
+
sinfo = sio.getvalue()
|
5682
|
+
sio.close()
|
5683
|
+
if sinfo[-1] == '\n':
|
5684
|
+
sinfo = sinfo[:-1]
|
5685
|
+
|
5686
|
+
return cls(
|
5687
|
+
file_path=f.f_code.co_filename,
|
5688
|
+
line_no=f.f_lineno or 0,
|
5689
|
+
func_name=f.f_code.co_name,
|
5690
|
+
stack_info=sinfo,
|
5691
|
+
)
|
5692
|
+
|
5693
|
+
@logging_context_info
|
5694
|
+
@ta.final
|
5695
|
+
class SourceFile(ta.NamedTuple):
|
5696
|
+
file_name: str
|
5697
|
+
module: str
|
5698
|
+
|
5699
|
+
@classmethod
|
5700
|
+
def build(cls, caller_file_path: ta.Optional[str]) -> ta.Optional['LoggingContextInfos.SourceFile']:
|
5701
|
+
if caller_file_path is None:
|
5702
|
+
return None
|
5703
|
+
|
5704
|
+
# https://github.com/python/cpython/blob/e709361fc87d0d9ab9c58033a0a7f2fef0ad43d2/Lib/logging/__init__.py#L331-L336 # noqa
|
5705
|
+
try:
|
5706
|
+
file_name = os.path.basename(caller_file_path)
|
5707
|
+
module = os.path.splitext(file_name)[0]
|
5708
|
+
except (TypeError, ValueError, AttributeError):
|
5709
|
+
return None
|
5710
|
+
|
5711
|
+
return cls(
|
5712
|
+
file_name=file_name,
|
5713
|
+
module=module,
|
5714
|
+
)
|
5715
|
+
|
5716
|
+
@logging_context_info
|
5717
|
+
@ta.final
|
5718
|
+
class Thread(ta.NamedTuple):
|
5719
|
+
ident: int
|
5720
|
+
native_id: ta.Optional[int]
|
5721
|
+
name: str
|
5722
|
+
|
5723
|
+
@classmethod
|
5724
|
+
def build(cls) -> 'LoggingContextInfos.Thread':
|
5725
|
+
return cls(
|
5726
|
+
ident=threading.get_ident(),
|
5727
|
+
native_id=threading.get_native_id() if hasattr(threading, 'get_native_id') else None,
|
5728
|
+
name=threading.current_thread().name,
|
5729
|
+
)
|
5730
|
+
|
5731
|
+
@logging_context_info
|
5732
|
+
@ta.final
|
5733
|
+
class Process(ta.NamedTuple):
|
5734
|
+
pid: int
|
5735
|
+
|
5736
|
+
@classmethod
|
5737
|
+
def build(cls) -> 'LoggingContextInfos.Process':
|
5738
|
+
return cls(
|
5739
|
+
pid=os.getpid(),
|
5740
|
+
)
|
5741
|
+
|
5742
|
+
@logging_context_info
|
5743
|
+
@ta.final
|
5744
|
+
class Multiprocessing(ta.NamedTuple):
|
5745
|
+
process_name: str
|
5746
|
+
|
5747
|
+
@classmethod
|
5748
|
+
def build(cls) -> ta.Optional['LoggingContextInfos.Multiprocessing']:
|
5749
|
+
# https://github.com/python/cpython/blob/e709361fc87d0d9ab9c58033a0a7f2fef0ad43d2/Lib/logging/__init__.py#L355-L364 # noqa
|
5750
|
+
if (mp := sys.modules.get('multiprocessing')) is None:
|
5751
|
+
return None
|
5752
|
+
|
5753
|
+
return cls(
|
5754
|
+
process_name=mp.current_process().name,
|
5755
|
+
)
|
5756
|
+
|
5757
|
+
@logging_context_info
|
5758
|
+
@ta.final
|
5759
|
+
class AsyncioTask(ta.NamedTuple):
|
5760
|
+
name: str
|
5761
|
+
|
5762
|
+
@classmethod
|
5763
|
+
def build(cls) -> ta.Optional['LoggingContextInfos.AsyncioTask']:
|
5764
|
+
# https://github.com/python/cpython/blob/e709361fc87d0d9ab9c58033a0a7f2fef0ad43d2/Lib/logging/__init__.py#L372-L377 # noqa
|
5765
|
+
if (asyncio := sys.modules.get('asyncio')) is None:
|
5766
|
+
return None
|
5767
|
+
|
5768
|
+
try:
|
5769
|
+
task = asyncio.current_task()
|
5770
|
+
except Exception: # noqa
|
5771
|
+
return None
|
5772
|
+
|
5773
|
+
if task is None:
|
5774
|
+
return None
|
5775
|
+
|
5776
|
+
return cls(
|
5777
|
+
name=task.get_name(), # Always non-None
|
5778
|
+
)
|
5779
|
+
|
5780
|
+
|
5781
|
+
##
|
5782
|
+
|
5783
|
+
|
5784
|
+
class UnexpectedLoggingStartTimeWarning(LoggingSetupWarning):
|
5785
|
+
pass
|
5786
|
+
|
5787
|
+
|
5788
|
+
def _check_logging_start_time() -> None:
|
5789
|
+
if (x := LoggingContextInfos.Time.get_std_start_ns()) < (t := time.time()):
|
5790
|
+
import warnings # noqa
|
5791
|
+
|
5792
|
+
warnings.warn(
|
5793
|
+
f'Unexpected logging start time detected: '
|
5794
|
+
f'get_std_start_ns={x}, '
|
5795
|
+
f'time.time()={t}',
|
5796
|
+
UnexpectedLoggingStartTimeWarning,
|
5595
5797
|
)
|
5596
5798
|
|
5597
5799
|
|
5800
|
+
_check_logging_start_time()
|
5801
|
+
|
5802
|
+
|
5598
5803
|
########################################
|
5599
5804
|
# ../../../omlish/logs/protocols.py
|
5600
5805
|
|
@@ -5602,6 +5807,7 @@ class LoggingCaller(ta.NamedTuple):
|
|
5602
5807
|
##
|
5603
5808
|
|
5604
5809
|
|
5810
|
+
@ta.runtime_checkable
|
5605
5811
|
class LoggerLike(ta.Protocol):
|
5606
5812
|
"""Satisfied by both our Logger and stdlib logging.Logger."""
|
5607
5813
|
|
@@ -5684,119 +5890,34 @@ class JsonLoggingFormatter(logging.Formatter):
|
|
5684
5890
|
|
5685
5891
|
|
5686
5892
|
########################################
|
5687
|
-
#
|
5893
|
+
# ../../interp/types.py
|
5688
5894
|
|
5689
5895
|
|
5690
5896
|
##
|
5691
5897
|
|
5692
5898
|
|
5693
|
-
|
5694
|
-
|
5695
|
-
|
5696
|
-
|
5697
|
-
|
5698
|
-
created: float
|
5699
|
-
msecs: float
|
5700
|
-
relative_created: float
|
5899
|
+
# See https://peps.python.org/pep-3149/
|
5900
|
+
INTERP_OPT_GLYPHS_BY_ATTR: ta.Mapping[str, str] = collections.OrderedDict([
|
5901
|
+
('debug', 'd'),
|
5902
|
+
('threaded', 't'),
|
5903
|
+
])
|
5701
5904
|
|
5702
|
-
|
5703
|
-
|
5704
|
-
|
5905
|
+
INTERP_OPT_ATTRS_BY_GLYPH: ta.Mapping[str, str] = collections.OrderedDict(
|
5906
|
+
(g, a) for a, g in INTERP_OPT_GLYPHS_BY_ATTR.items()
|
5907
|
+
)
|
5705
5908
|
|
5706
|
-
# Before 3.13.0b1 this will be `time.time()`, a float of seconds. After that, it will be `time.time_ns()`, an
|
5707
|
-
# int.
|
5708
|
-
#
|
5709
|
-
# See:
|
5710
|
-
# - https://github.com/python/cpython/commit/1316692e8c7c1e1f3b6639e51804f9db5ed892ea
|
5711
|
-
#
|
5712
|
-
if isinstance(x, float):
|
5713
|
-
return int(x * 1e9)
|
5714
|
-
else:
|
5715
|
-
return x
|
5716
5909
|
|
5717
|
-
|
5718
|
-
|
5719
|
-
|
5720
|
-
|
5721
|
-
*,
|
5722
|
-
start_time_ns: ta.Optional[int] = None,
|
5723
|
-
) -> 'LoggingTimeFields':
|
5724
|
-
# https://github.com/python/cpython/commit/1316692e8c7c1e1f3b6639e51804f9db5ed892ea
|
5725
|
-
created = time_ns / 1e9 # ns to float seconds
|
5726
|
-
|
5727
|
-
# Get the number of whole milliseconds (0-999) in the fractional part of seconds.
|
5728
|
-
# Eg: 1_677_903_920_999_998_503 ns --> 999_998_503 ns--> 999 ms
|
5729
|
-
# Convert to float by adding 0.0 for historical reasons. See gh-89047
|
5730
|
-
msecs = (time_ns % 1_000_000_000) // 1_000_000 + 0.0
|
5731
|
-
|
5732
|
-
# https://github.com/python/cpython/commit/1500a23f33f5a6d052ff1ef6383d9839928b8ff1
|
5733
|
-
if msecs == 999.0 and int(created) != time_ns // 1_000_000_000:
|
5734
|
-
# ns -> sec conversion can round up, e.g:
|
5735
|
-
# 1_677_903_920_999_999_900 ns --> 1_677_903_921.0 sec
|
5736
|
-
msecs = 0.0
|
5737
|
-
|
5738
|
-
if start_time_ns is None:
|
5739
|
-
start_time_ns = cls.get_std_start_time_ns()
|
5740
|
-
relative_created = (time_ns - start_time_ns) / 1e6
|
5910
|
+
@dc.dataclass(frozen=True)
|
5911
|
+
class InterpOpts:
|
5912
|
+
threaded: bool = False
|
5913
|
+
debug: bool = False
|
5741
5914
|
|
5742
|
-
|
5743
|
-
|
5744
|
-
msecs,
|
5745
|
-
relative_created,
|
5746
|
-
)
|
5915
|
+
def __str__(self) -> str:
|
5916
|
+
return ''.join(g for a, g in INTERP_OPT_GLYPHS_BY_ATTR.items() if getattr(self, a))
|
5747
5917
|
|
5748
|
-
|
5749
|
-
|
5750
|
-
|
5751
|
-
|
5752
|
-
class UnexpectedLoggingStartTimeWarning(LoggingSetupWarning):
|
5753
|
-
pass
|
5754
|
-
|
5755
|
-
|
5756
|
-
def _check_logging_start_time() -> None:
|
5757
|
-
if (x := LoggingTimeFields.get_std_start_time_ns()) < (t := time.time()):
|
5758
|
-
import warnings # noqa
|
5759
|
-
|
5760
|
-
warnings.warn(
|
5761
|
-
f'Unexpected logging start time detected: '
|
5762
|
-
f'get_std_start_time_ns={x}, '
|
5763
|
-
f'time.time()={t}',
|
5764
|
-
UnexpectedLoggingStartTimeWarning,
|
5765
|
-
)
|
5766
|
-
|
5767
|
-
|
5768
|
-
_check_logging_start_time()
|
5769
|
-
|
5770
|
-
|
5771
|
-
########################################
|
5772
|
-
# ../../interp/types.py
|
5773
|
-
|
5774
|
-
|
5775
|
-
##
|
5776
|
-
|
5777
|
-
|
5778
|
-
# See https://peps.python.org/pep-3149/
|
5779
|
-
INTERP_OPT_GLYPHS_BY_ATTR: ta.Mapping[str, str] = collections.OrderedDict([
|
5780
|
-
('debug', 'd'),
|
5781
|
-
('threaded', 't'),
|
5782
|
-
])
|
5783
|
-
|
5784
|
-
INTERP_OPT_ATTRS_BY_GLYPH: ta.Mapping[str, str] = collections.OrderedDict(
|
5785
|
-
(g, a) for a, g in INTERP_OPT_GLYPHS_BY_ATTR.items()
|
5786
|
-
)
|
5787
|
-
|
5788
|
-
|
5789
|
-
@dc.dataclass(frozen=True)
|
5790
|
-
class InterpOpts:
|
5791
|
-
threaded: bool = False
|
5792
|
-
debug: bool = False
|
5793
|
-
|
5794
|
-
def __str__(self) -> str:
|
5795
|
-
return ''.join(g for a, g in INTERP_OPT_GLYPHS_BY_ATTR.items() if getattr(self, a))
|
5796
|
-
|
5797
|
-
@classmethod
|
5798
|
-
def parse(cls, s: str) -> 'InterpOpts':
|
5799
|
-
return cls(**{INTERP_OPT_ATTRS_BY_GLYPH[g]: True for g in s})
|
5918
|
+
@classmethod
|
5919
|
+
def parse(cls, s: str) -> 'InterpOpts':
|
5920
|
+
return cls(**{INTERP_OPT_ATTRS_BY_GLYPH[g]: True for g in s})
|
5800
5921
|
|
5801
5922
|
@classmethod
|
5802
5923
|
def parse_suffix(cls, s: str) -> ta.Tuple[str, 'InterpOpts']:
|
@@ -6981,68 +7102,36 @@ inj = InjectionApi()
|
|
6981
7102
|
|
6982
7103
|
|
6983
7104
|
class LoggingContext(Abstract):
|
6984
|
-
@property
|
6985
|
-
@abc.abstractmethod
|
6986
|
-
def level(self) -> NamedLogLevel:
|
6987
|
-
raise NotImplementedError
|
6988
|
-
|
6989
|
-
#
|
6990
|
-
|
6991
|
-
@property
|
6992
|
-
@abc.abstractmethod
|
6993
|
-
def time_ns(self) -> int:
|
6994
|
-
raise NotImplementedError
|
6995
|
-
|
6996
|
-
@property
|
6997
7105
|
@abc.abstractmethod
|
6998
|
-
def
|
7106
|
+
def get_info(self, ty: ta.Type[LoggingContextInfoT]) -> ta.Optional[LoggingContextInfoT]:
|
6999
7107
|
raise NotImplementedError
|
7000
7108
|
|
7001
|
-
|
7109
|
+
@ta.final
|
7110
|
+
def __getitem__(self, ty: ta.Type[LoggingContextInfoT]) -> ta.Optional[LoggingContextInfoT]:
|
7111
|
+
return self.get_info(ty)
|
7002
7112
|
|
7003
|
-
@
|
7004
|
-
|
7005
|
-
|
7006
|
-
|
7113
|
+
@ta.final
|
7114
|
+
def must_get_info(self, ty: ta.Type[LoggingContextInfoT]) -> LoggingContextInfoT:
|
7115
|
+
if (info := self.get_info(ty)) is None:
|
7116
|
+
raise TypeError(f'LoggingContextInfo absent: {ty}')
|
7117
|
+
return info
|
7007
7118
|
|
7008
|
-
|
7009
|
-
@abc.abstractmethod
|
7010
|
-
def exc_info_tuple(self) -> ta.Optional[LoggingExcInfoTuple]:
|
7011
|
-
raise NotImplementedError
|
7119
|
+
##
|
7012
7120
|
|
7013
|
-
#
|
7014
7121
|
|
7122
|
+
class CaptureLoggingContext(LoggingContext, Abstract):
|
7015
7123
|
@abc.abstractmethod
|
7016
|
-
def
|
7017
|
-
|
7124
|
+
def set_basic(
|
7125
|
+
self,
|
7126
|
+
name: str,
|
7018
7127
|
|
7019
|
-
|
7020
|
-
|
7128
|
+
msg: ta.Union[str, tuple, LoggingMsgFn],
|
7129
|
+
args: tuple,
|
7130
|
+
) -> 'CaptureLoggingContext':
|
7021
7131
|
raise NotImplementedError
|
7022
7132
|
|
7023
7133
|
#
|
7024
7134
|
|
7025
|
-
@abc.abstractmethod
|
7026
|
-
def thread(self) -> ta.Optional[LoggingThreadInfo]:
|
7027
|
-
raise NotImplementedError
|
7028
|
-
|
7029
|
-
@abc.abstractmethod
|
7030
|
-
def process(self) -> ta.Optional[LoggingProcessInfo]:
|
7031
|
-
raise NotImplementedError
|
7032
|
-
|
7033
|
-
@abc.abstractmethod
|
7034
|
-
def multiprocessing(self) -> ta.Optional[LoggingMultiprocessingInfo]:
|
7035
|
-
raise NotImplementedError
|
7036
|
-
|
7037
|
-
@abc.abstractmethod
|
7038
|
-
def asyncio_task(self) -> ta.Optional[LoggingAsyncioTaskInfo]:
|
7039
|
-
raise NotImplementedError
|
7040
|
-
|
7041
|
-
|
7042
|
-
##
|
7043
|
-
|
7044
|
-
|
7045
|
-
class CaptureLoggingContext(LoggingContext, Abstract):
|
7046
7135
|
class AlreadyCapturedError(Exception):
|
7047
7136
|
pass
|
7048
7137
|
|
@@ -7073,80 +7162,50 @@ class CaptureLoggingContextImpl(CaptureLoggingContext):
|
|
7073
7162
|
|
7074
7163
|
exc_info: LoggingExcInfoArg = False,
|
7075
7164
|
|
7076
|
-
caller: ta.Union[
|
7165
|
+
caller: ta.Union[LoggingContextInfos.Caller, ta.Type[NOT_SET], None] = NOT_SET,
|
7077
7166
|
stack_offset: int = 0,
|
7078
7167
|
stack_info: bool = False,
|
7079
7168
|
) -> None:
|
7080
|
-
|
7081
|
-
|
7082
|
-
#
|
7169
|
+
# TODO: Name, Msg, Extra
|
7083
7170
|
|
7084
7171
|
if time_ns is None:
|
7085
7172
|
time_ns = time.time_ns()
|
7086
|
-
self._time_ns: int = time_ns
|
7087
|
-
|
7088
|
-
#
|
7089
|
-
|
7090
|
-
if exc_info is True:
|
7091
|
-
sys_exc_info = sys.exc_info()
|
7092
|
-
if sys_exc_info[0] is not None:
|
7093
|
-
exc_info = sys_exc_info
|
7094
|
-
else:
|
7095
|
-
exc_info = None
|
7096
|
-
elif exc_info is False:
|
7097
|
-
exc_info = None
|
7098
|
-
|
7099
|
-
if exc_info is not None:
|
7100
|
-
self._exc_info: ta.Optional[LoggingExcInfo] = exc_info
|
7101
|
-
if isinstance(exc_info, BaseException):
|
7102
|
-
self._exc_info_tuple: ta.Optional[LoggingExcInfoTuple] = (type(exc_info), exc_info, exc_info.__traceback__) # noqa
|
7103
|
-
else:
|
7104
|
-
self._exc_info_tuple = exc_info
|
7105
7173
|
|
7106
|
-
|
7174
|
+
self._infos: ta.Dict[ta.Type[LoggingContextInfo], LoggingContextInfo] = {}
|
7175
|
+
self._set_info(
|
7176
|
+
LoggingContextInfos.Level.build(level),
|
7177
|
+
LoggingContextInfos.Time.build(time_ns),
|
7178
|
+
LoggingContextInfos.Exc.build(exc_info),
|
7179
|
+
)
|
7107
7180
|
|
7108
7181
|
if caller is not CaptureLoggingContextImpl.NOT_SET:
|
7109
|
-
self.
|
7182
|
+
self._infos[LoggingContextInfos.Caller] = caller
|
7110
7183
|
else:
|
7111
7184
|
self._stack_offset = stack_offset
|
7112
7185
|
self._stack_info = stack_info
|
7113
7186
|
|
7114
|
-
|
7115
|
-
|
7116
|
-
|
7117
|
-
|
7118
|
-
return self
|
7119
|
-
|
7120
|
-
#
|
7121
|
-
|
7122
|
-
@property
|
7123
|
-
def time_ns(self) -> int:
|
7124
|
-
return self._time_ns
|
7125
|
-
|
7126
|
-
_times: LoggingTimeFields
|
7127
|
-
|
7128
|
-
@property
|
7129
|
-
def times(self) -> LoggingTimeFields:
|
7130
|
-
try:
|
7131
|
-
return self._times
|
7132
|
-
except AttributeError:
|
7133
|
-
pass
|
7134
|
-
|
7135
|
-
times = self._times = LoggingTimeFields.build(self.time_ns)
|
7136
|
-
return times
|
7187
|
+
def _set_info(self, *infos: ta.Optional[LoggingContextInfo]) -> 'CaptureLoggingContextImpl':
|
7188
|
+
for info in infos:
|
7189
|
+
if info is not None:
|
7190
|
+
self._infos[type(info)] = info
|
7191
|
+
return self
|
7137
7192
|
|
7138
|
-
|
7193
|
+
def get_info(self, ty: ta.Type[LoggingContextInfoT]) -> ta.Optional[LoggingContextInfoT]:
|
7194
|
+
return self._infos.get(ty)
|
7139
7195
|
|
7140
|
-
|
7141
|
-
_exc_info_tuple: ta.Optional[LoggingExcInfoTuple] = None
|
7196
|
+
##
|
7142
7197
|
|
7143
|
-
|
7144
|
-
|
7145
|
-
|
7198
|
+
def set_basic(
|
7199
|
+
self,
|
7200
|
+
name: str,
|
7146
7201
|
|
7147
|
-
|
7148
|
-
|
7149
|
-
|
7202
|
+
msg: ta.Union[str, tuple, LoggingMsgFn],
|
7203
|
+
args: tuple,
|
7204
|
+
) -> 'CaptureLoggingContextImpl':
|
7205
|
+
return self._set_info(
|
7206
|
+
LoggingContextInfos.Name(name),
|
7207
|
+
LoggingContextInfos.Msg.build(msg, *args),
|
7208
|
+
)
|
7150
7209
|
|
7151
7210
|
##
|
7152
7211
|
|
@@ -7160,74 +7219,28 @@ class CaptureLoggingContextImpl(CaptureLoggingContext):
|
|
7160
7219
|
|
7161
7220
|
_has_captured: bool = False
|
7162
7221
|
|
7163
|
-
_caller: ta.Optional[LoggingCaller]
|
7164
|
-
_source_file: ta.Optional[LoggingSourceFileInfo]
|
7165
|
-
|
7166
|
-
_thread: ta.Optional[LoggingThreadInfo]
|
7167
|
-
_process: ta.Optional[LoggingProcessInfo]
|
7168
|
-
_multiprocessing: ta.Optional[LoggingMultiprocessingInfo]
|
7169
|
-
_asyncio_task: ta.Optional[LoggingAsyncioTaskInfo]
|
7170
|
-
|
7171
7222
|
def capture(self) -> None:
|
7172
7223
|
if self._has_captured:
|
7173
7224
|
raise CaptureLoggingContextImpl.AlreadyCapturedError
|
7174
7225
|
self._has_captured = True
|
7175
7226
|
|
7176
|
-
if not
|
7177
|
-
self.
|
7227
|
+
if LoggingContextInfos.Caller not in self._infos:
|
7228
|
+
self._set_info(LoggingContextInfos.Caller.build(
|
7178
7229
|
self._stack_offset + 1,
|
7179
7230
|
stack_info=self._stack_info,
|
7180
|
-
)
|
7181
|
-
|
7182
|
-
if (caller := self._caller) is not None:
|
7183
|
-
self._source_file = LoggingSourceFileInfo.build(caller.file_path)
|
7184
|
-
else:
|
7185
|
-
self._source_file = None
|
7186
|
-
|
7187
|
-
self._thread = LoggingThreadInfo.build()
|
7188
|
-
self._process = LoggingProcessInfo.build()
|
7189
|
-
self._multiprocessing = LoggingMultiprocessingInfo.build()
|
7190
|
-
self._asyncio_task = LoggingAsyncioTaskInfo.build()
|
7191
|
-
|
7192
|
-
#
|
7193
|
-
|
7194
|
-
def caller(self) -> ta.Optional[LoggingCaller]:
|
7195
|
-
try:
|
7196
|
-
return self._caller
|
7197
|
-
except AttributeError:
|
7198
|
-
raise CaptureLoggingContext.NotCapturedError from None
|
7199
|
-
|
7200
|
-
def source_file(self) -> ta.Optional[LoggingSourceFileInfo]:
|
7201
|
-
try:
|
7202
|
-
return self._source_file
|
7203
|
-
except AttributeError:
|
7204
|
-
raise CaptureLoggingContext.NotCapturedError from None
|
7205
|
-
|
7206
|
-
#
|
7207
|
-
|
7208
|
-
def thread(self) -> ta.Optional[LoggingThreadInfo]:
|
7209
|
-
try:
|
7210
|
-
return self._thread
|
7211
|
-
except AttributeError:
|
7212
|
-
raise CaptureLoggingContext.NotCapturedError from None
|
7213
|
-
|
7214
|
-
def process(self) -> ta.Optional[LoggingProcessInfo]:
|
7215
|
-
try:
|
7216
|
-
return self._process
|
7217
|
-
except AttributeError:
|
7218
|
-
raise CaptureLoggingContext.NotCapturedError from None
|
7231
|
+
))
|
7219
7232
|
|
7220
|
-
|
7221
|
-
|
7222
|
-
|
7223
|
-
|
7224
|
-
raise CaptureLoggingContext.NotCapturedError from None
|
7233
|
+
if (caller := self[LoggingContextInfos.Caller]) is not None:
|
7234
|
+
self._set_info(LoggingContextInfos.SourceFile.build(
|
7235
|
+
caller.file_path,
|
7236
|
+
))
|
7225
7237
|
|
7226
|
-
|
7227
|
-
|
7228
|
-
|
7229
|
-
|
7230
|
-
|
7238
|
+
self._set_info(
|
7239
|
+
LoggingContextInfos.Thread.build(),
|
7240
|
+
LoggingContextInfos.Process.build(),
|
7241
|
+
LoggingContextInfos.Multiprocessing.build(),
|
7242
|
+
LoggingContextInfos.AsyncioTask.build(),
|
7243
|
+
)
|
7231
7244
|
|
7232
7245
|
|
7233
7246
|
########################################
|
@@ -7581,7 +7594,6 @@ InterpProviders = ta.NewType('InterpProviders', ta.Sequence[InterpProvider])
|
|
7581
7594
|
|
7582
7595
|
|
7583
7596
|
class AnyLogger(Abstract, ta.Generic[T]):
|
7584
|
-
@ta.final
|
7585
7597
|
def is_enabled_for(self, level: LogLevel) -> bool:
|
7586
7598
|
return level >= self.get_effective_level()
|
7587
7599
|
|
@@ -7727,36 +7739,6 @@ class AnyLogger(Abstract, ta.Generic[T]):
|
|
7727
7739
|
|
7728
7740
|
##
|
7729
7741
|
|
7730
|
-
@classmethod
|
7731
|
-
def _prepare_msg_args(cls, msg: ta.Union[str, tuple, LoggingMsgFn], *args: ta.Any) -> ta.Tuple[str, tuple]:
|
7732
|
-
if callable(msg):
|
7733
|
-
if args:
|
7734
|
-
raise TypeError(f'Must not provide both a message function and args: {msg=} {args=}')
|
7735
|
-
x = msg()
|
7736
|
-
if isinstance(x, str):
|
7737
|
-
return x, ()
|
7738
|
-
elif isinstance(x, tuple):
|
7739
|
-
if x:
|
7740
|
-
return x[0], x[1:]
|
7741
|
-
else:
|
7742
|
-
return '', ()
|
7743
|
-
else:
|
7744
|
-
raise TypeError(x)
|
7745
|
-
|
7746
|
-
elif isinstance(msg, tuple):
|
7747
|
-
if args:
|
7748
|
-
raise TypeError(f'Must not provide both a tuple message and args: {msg=} {args=}')
|
7749
|
-
if msg:
|
7750
|
-
return msg[0], msg[1:]
|
7751
|
-
else:
|
7752
|
-
return '', ()
|
7753
|
-
|
7754
|
-
elif isinstance(msg, str):
|
7755
|
-
return msg, args
|
7756
|
-
|
7757
|
-
else:
|
7758
|
-
raise TypeError(msg)
|
7759
|
-
|
7760
7742
|
@abc.abstractmethod
|
7761
7743
|
def _log(self, ctx: CaptureLoggingContext, msg: ta.Union[str, tuple, LoggingMsgFn], *args: ta.Any, **kwargs: ta.Any) -> T: # noqa
|
7762
7744
|
raise NotImplementedError
|
@@ -7780,7 +7762,7 @@ class AsyncLogger(AnyLogger[ta.Awaitable[None]], Abstract):
|
|
7780
7762
|
class AnyNopLogger(AnyLogger[T], Abstract):
|
7781
7763
|
@ta.final
|
7782
7764
|
def get_effective_level(self) -> LogLevel:
|
7783
|
-
return 999
|
7765
|
+
return -999
|
7784
7766
|
|
7785
7767
|
|
7786
7768
|
@ta.final
|
@@ -7797,137 +7779,543 @@ class AsyncNopLogger(AnyNopLogger[ta.Awaitable[None]], AsyncLogger):
|
|
7797
7779
|
|
7798
7780
|
########################################
|
7799
7781
|
# ../../../omlish/logs/std/records.py
|
7782
|
+
"""
|
7783
|
+
TODO:
|
7784
|
+
- TypedDict?
|
7785
|
+
"""
|
7800
7786
|
|
7801
7787
|
|
7802
7788
|
##
|
7803
7789
|
|
7804
7790
|
|
7805
|
-
|
7806
|
-
#
|
7807
|
-
#
|
7808
|
-
#
|
7809
|
-
#
|
7810
|
-
# - https://github.com/python/cpython/blob/
|
7811
|
-
#
|
7812
|
-
#
|
7813
|
-
# - name: str
|
7814
|
-
# - level: int
|
7815
|
-
# - pathname: str - Confusingly referred to as `fn` before the LogRecord ctor. May be empty or "(unknown file)".
|
7816
|
-
# - lineno: int - May be 0.
|
7817
|
-
# - msg: str
|
7818
|
-
# - args: tuple | dict | 1-tuple[dict]
|
7819
|
-
# - exc_info: LoggingExcInfoTuple | None
|
7820
|
-
# - func: str | None = None -> funcName
|
7821
|
-
# - sinfo: str | None = None -> stack_info
|
7822
|
-
#
|
7823
|
-
KNOWN_STD_LOGGING_RECORD_ATTRS: ta.Dict[str, ta.Any] = dict(
|
7824
|
-
# Name of the logger used to log the call. Unmodified by ctor.
|
7825
|
-
name=str,
|
7791
|
+
class LoggingContextInfoRecordAdapters:
|
7792
|
+
# Ref:
|
7793
|
+
# - https://docs.python.org/3/library/logging.html#logrecord-attributes
|
7794
|
+
#
|
7795
|
+
# LogRecord:
|
7796
|
+
# - https://github.com/python/cpython/blob/39b2f82717a69dde7212bc39b673b0f55c99e6a3/Lib/logging/__init__.py#L276 (3.8) # noqa
|
7797
|
+
# - https://github.com/python/cpython/blob/f070f54c5f4a42c7c61d1d5d3b8f3b7203b4a0fb/Lib/logging/__init__.py#L286 (~3.14) # noqa
|
7798
|
+
#
|
7826
7799
|
|
7827
|
-
|
7828
|
-
|
7829
|
-
msg=str,
|
7800
|
+
def __new__(cls, *args, **kwargs): # noqa
|
7801
|
+
raise TypeError
|
7830
7802
|
|
7831
|
-
|
7832
|
-
|
7833
|
-
|
7834
|
-
|
7803
|
+
class Adapter(Abstract, ta.Generic[T]):
|
7804
|
+
@property
|
7805
|
+
@abc.abstractmethod
|
7806
|
+
def info_cls(self) -> ta.Type[LoggingContextInfo]:
|
7807
|
+
raise NotImplementedError
|
7835
7808
|
|
7836
|
-
|
7809
|
+
#
|
7837
7810
|
|
7838
|
-
|
7839
|
-
|
7840
|
-
|
7811
|
+
@ta.final
|
7812
|
+
class NOT_SET: # noqa
|
7813
|
+
def __new__(cls, *args, **kwargs): # noqa
|
7814
|
+
raise TypeError
|
7841
7815
|
|
7842
|
-
|
7843
|
-
|
7816
|
+
class RecordAttr(ta.NamedTuple):
|
7817
|
+
name: str
|
7818
|
+
type: ta.Any
|
7819
|
+
default: ta.Any
|
7844
7820
|
|
7845
|
-
|
7821
|
+
# @abc.abstractmethod
|
7822
|
+
record_attrs: ta.ClassVar[ta.Mapping[str, RecordAttr]]
|
7846
7823
|
|
7847
|
-
|
7848
|
-
|
7849
|
-
|
7824
|
+
@property
|
7825
|
+
@abc.abstractmethod
|
7826
|
+
def _record_attrs(self) -> ta.Union[
|
7827
|
+
ta.Mapping[str, ta.Any],
|
7828
|
+
ta.Mapping[str, ta.Tuple[ta.Any, ta.Any]],
|
7829
|
+
]:
|
7830
|
+
raise NotImplementedError
|
7850
7831
|
|
7851
|
-
|
7852
|
-
filename=str,
|
7832
|
+
#
|
7853
7833
|
|
7854
|
-
|
7855
|
-
|
7856
|
-
|
7834
|
+
@abc.abstractmethod
|
7835
|
+
def context_to_record(self, ctx: LoggingContext) -> ta.Mapping[str, ta.Any]:
|
7836
|
+
raise NotImplementedError
|
7857
7837
|
|
7858
|
-
|
7838
|
+
#
|
7859
7839
|
|
7860
|
-
|
7861
|
-
|
7840
|
+
@abc.abstractmethod
|
7841
|
+
def record_to_info(self, rec: logging.LogRecord) -> ta.Optional[T]:
|
7842
|
+
raise NotImplementedError
|
7862
7843
|
|
7863
|
-
|
7864
|
-
exc_text=ta.Optional[str],
|
7844
|
+
#
|
7865
7845
|
|
7866
|
-
|
7846
|
+
def __init_subclass__(cls, **kwargs: ta.Any) -> None:
|
7847
|
+
super().__init_subclass__(**kwargs)
|
7867
7848
|
|
7868
|
-
|
7869
|
-
|
7870
|
-
# unmodified. Mostly set, if requested, by `Logger.findCaller`, to `traceback.print_stack(f)`, but prepended with
|
7871
|
-
# the literal "Stack (most recent call last):\n", and stripped of exactly one trailing `\n` if present.
|
7872
|
-
stack_info=ta.Optional[str],
|
7849
|
+
if Abstract in cls.__bases__:
|
7850
|
+
return
|
7873
7851
|
|
7874
|
-
|
7875
|
-
|
7876
|
-
|
7852
|
+
if 'record_attrs' in cls.__dict__:
|
7853
|
+
raise TypeError(cls)
|
7854
|
+
if not isinstance(ra := cls.__dict__['_record_attrs'], collections.abc.Mapping):
|
7855
|
+
raise TypeError(ra)
|
7856
|
+
|
7857
|
+
rd: ta.Dict[str, LoggingContextInfoRecordAdapters.Adapter.RecordAttr] = {}
|
7858
|
+
for n, v in ra.items():
|
7859
|
+
if not n or not isinstance(n, str) or n in rd:
|
7860
|
+
raise AttributeError(n)
|
7861
|
+
if isinstance(v, tuple):
|
7862
|
+
t, d = v
|
7863
|
+
else:
|
7864
|
+
t, d = v, cls.NOT_SET
|
7865
|
+
rd[n] = cls.RecordAttr(
|
7866
|
+
name=n,
|
7867
|
+
type=t,
|
7868
|
+
default=d,
|
7869
|
+
)
|
7870
|
+
cls.record_attrs = rd
|
7877
7871
|
|
7878
|
-
|
7879
|
-
|
7880
|
-
|
7872
|
+
class RequiredAdapter(Adapter[T], Abstract):
|
7873
|
+
@property
|
7874
|
+
@abc.abstractmethod
|
7875
|
+
def _record_attrs(self) -> ta.Mapping[str, ta.Any]:
|
7876
|
+
raise NotImplementedError
|
7881
7877
|
|
7882
|
-
|
7878
|
+
#
|
7883
7879
|
|
7884
|
-
|
7885
|
-
|
7886
|
-
|
7887
|
-
|
7888
|
-
|
7889
|
-
|
7890
|
-
created=float,
|
7880
|
+
@ta.final
|
7881
|
+
def context_to_record(self, ctx: LoggingContext) -> ta.Mapping[str, ta.Any]:
|
7882
|
+
if (info := ctx.get_info(self.info_cls)) is not None:
|
7883
|
+
return self._info_to_record(info)
|
7884
|
+
else:
|
7885
|
+
raise TypeError # FIXME: fallback?
|
7891
7886
|
|
7892
|
-
|
7893
|
-
|
7887
|
+
@abc.abstractmethod
|
7888
|
+
def _info_to_record(self, info: T) -> ta.Mapping[str, ta.Any]:
|
7889
|
+
raise NotImplementedError
|
7894
7890
|
|
7895
|
-
|
7896
|
-
relativeCreated=float,
|
7891
|
+
#
|
7897
7892
|
|
7898
|
-
|
7893
|
+
@abc.abstractmethod
|
7894
|
+
def record_to_info(self, rec: logging.LogRecord) -> T:
|
7895
|
+
raise NotImplementedError
|
7896
|
+
|
7897
|
+
#
|
7899
7898
|
|
7900
|
-
|
7901
|
-
|
7899
|
+
def __init_subclass__(cls, **kwargs: ta.Any) -> None:
|
7900
|
+
super().__init_subclass__(**kwargs)
|
7902
7901
|
|
7903
|
-
|
7904
|
-
|
7902
|
+
if any(a.default is not cls.NOT_SET for a in cls.record_attrs.values()):
|
7903
|
+
raise TypeError(cls.record_attrs)
|
7905
7904
|
|
7906
|
-
|
7905
|
+
class OptionalAdapter(Adapter[T], Abstract, ta.Generic[T]):
|
7906
|
+
@property
|
7907
|
+
@abc.abstractmethod
|
7908
|
+
def _record_attrs(self) -> ta.Mapping[str, ta.Tuple[ta.Any, ta.Any]]:
|
7909
|
+
raise NotImplementedError
|
7910
|
+
|
7911
|
+
record_defaults: ta.ClassVar[ta.Mapping[str, ta.Any]]
|
7912
|
+
|
7913
|
+
#
|
7914
|
+
|
7915
|
+
@ta.final
|
7916
|
+
def context_to_record(self, ctx: LoggingContext) -> ta.Mapping[str, ta.Any]:
|
7917
|
+
if (info := ctx.get_info(self.info_cls)) is not None:
|
7918
|
+
return self._info_to_record(info)
|
7919
|
+
else:
|
7920
|
+
return self.record_defaults
|
7921
|
+
|
7922
|
+
@abc.abstractmethod
|
7923
|
+
def _info_to_record(self, info: T) -> ta.Mapping[str, ta.Any]:
|
7924
|
+
raise NotImplementedError
|
7925
|
+
|
7926
|
+
#
|
7927
|
+
|
7928
|
+
def __init_subclass__(cls, **kwargs: ta.Any) -> None:
|
7929
|
+
super().__init_subclass__(**kwargs)
|
7930
|
+
|
7931
|
+
dd: ta.Dict[str, ta.Any] = {a.name: a.default for a in cls.record_attrs.values()}
|
7932
|
+
if any(d is cls.NOT_SET for d in dd.values()):
|
7933
|
+
raise TypeError(cls.record_attrs)
|
7934
|
+
cls.record_defaults = dd
|
7907
7935
|
|
7908
|
-
# Process name if available. Set to None if `logging.logMultiprocessing` is not truthy. Otherwise, set to
|
7909
|
-
# 'MainProcess', then `sys.modules.get('multiprocessing').current_process().name` if that works, otherwise remains
|
7910
|
-
# as 'MainProcess'.
|
7911
7936
|
#
|
7912
|
-
|
7937
|
+
|
7938
|
+
class Name(RequiredAdapter[LoggingContextInfos.Name]):
|
7939
|
+
info_cls: ta.ClassVar[ta.Type[LoggingContextInfos.Name]] = LoggingContextInfos.Name
|
7940
|
+
|
7941
|
+
_record_attrs: ta.ClassVar[ta.Mapping[str, ta.Any]] = dict(
|
7942
|
+
# Name of the logger used to log the call. Unmodified by ctor.
|
7943
|
+
name=str,
|
7944
|
+
)
|
7945
|
+
|
7946
|
+
def _info_to_record(self, info: LoggingContextInfos.Name) -> ta.Mapping[str, ta.Any]:
|
7947
|
+
return dict(
|
7948
|
+
name=info.name,
|
7949
|
+
)
|
7950
|
+
|
7951
|
+
def record_to_info(self, rec: logging.LogRecord) -> LoggingContextInfos.Name:
|
7952
|
+
return LoggingContextInfos.Name(
|
7953
|
+
name=rec.name,
|
7954
|
+
)
|
7955
|
+
|
7956
|
+
class Level(RequiredAdapter[LoggingContextInfos.Level]):
|
7957
|
+
info_cls: ta.ClassVar[ta.Type[LoggingContextInfos.Level]] = LoggingContextInfos.Level
|
7958
|
+
|
7959
|
+
_record_attrs: ta.ClassVar[ta.Mapping[str, ta.Any]] = dict(
|
7960
|
+
# Text logging level for the message ('DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL'). Set to
|
7961
|
+
# `getLevelName(level)`.
|
7962
|
+
levelname=str,
|
7963
|
+
|
7964
|
+
# Numeric logging level for the message (DEBUG, INFO, WARNING, ERROR, CRITICAL). Unmodified by ctor.
|
7965
|
+
levelno=int,
|
7966
|
+
)
|
7967
|
+
|
7968
|
+
def _info_to_record(self, info: LoggingContextInfos.Level) -> ta.Mapping[str, ta.Any]:
|
7969
|
+
return dict(
|
7970
|
+
levelname=info.name,
|
7971
|
+
levelno=int(info.level),
|
7972
|
+
)
|
7973
|
+
|
7974
|
+
def record_to_info(self, rec: logging.LogRecord) -> LoggingContextInfos.Level:
|
7975
|
+
return LoggingContextInfos.Level.build(rec.levelno)
|
7976
|
+
|
7977
|
+
class Msg(RequiredAdapter[LoggingContextInfos.Msg]):
|
7978
|
+
info_cls: ta.ClassVar[ta.Type[LoggingContextInfos.Msg]] = LoggingContextInfos.Msg
|
7979
|
+
|
7980
|
+
_record_attrs: ta.ClassVar[ta.Mapping[str, ta.Any]] = dict(
|
7981
|
+
# The format string passed in the original logging call. Merged with args to produce message, or an
|
7982
|
+
# arbitrary object (see Using arbitrary objects as messages). Unmodified by ctor.
|
7983
|
+
msg=str,
|
7984
|
+
|
7985
|
+
# The tuple of arguments merged into msg to produce message, or a dict whose values are used for the merge
|
7986
|
+
# (when there is only one argument, and it is a dictionary). Ctor will transform a 1-tuple containing a
|
7987
|
+
# Mapping into just the mapping, but is otherwise unmodified.
|
7988
|
+
args=ta.Union[tuple, dict, None],
|
7989
|
+
)
|
7990
|
+
|
7991
|
+
def _info_to_record(self, info: LoggingContextInfos.Msg) -> ta.Mapping[str, ta.Any]:
|
7992
|
+
return dict(
|
7993
|
+
msg=info.msg,
|
7994
|
+
args=info.args,
|
7995
|
+
)
|
7996
|
+
|
7997
|
+
def record_to_info(self, rec: logging.LogRecord) -> LoggingContextInfos.Msg:
|
7998
|
+
return LoggingContextInfos.Msg(
|
7999
|
+
msg=rec.msg,
|
8000
|
+
args=rec.args,
|
8001
|
+
)
|
8002
|
+
|
8003
|
+
# FIXME: handled specially - all unknown attrs on LogRecord
|
8004
|
+
# class Extra(Adapter[LoggingContextInfos.Extra]):
|
8005
|
+
# _record_attrs: ta.ClassVar[ta.Mapping[str, ta.Union[ta.Any, ta.Tuple[ta.Any, ta.Any]]]] = dict()
|
7913
8006
|
#
|
7914
|
-
#
|
7915
|
-
#
|
8007
|
+
# def info_to_record(self, info: ta.Optional[LoggingContextInfos.Extra]) -> ta.Mapping[str, ta.Any]:
|
8008
|
+
# # FIXME:
|
8009
|
+
# # if extra is not None:
|
8010
|
+
# # for key in extra:
|
8011
|
+
# # if (key in ["message", "asctime"]) or (key in rv.__dict__):
|
8012
|
+
# # raise KeyError("Attempt to overwrite %r in LogRecord" % key)
|
8013
|
+
# # rv.__dict__[key] = extra[key]
|
8014
|
+
# return dict()
|
7916
8015
|
#
|
7917
|
-
|
8016
|
+
# def record_to_info(self, rec: logging.LogRecord) -> ta.Optional[LoggingContextInfos.Extra]:
|
8017
|
+
# return None
|
8018
|
+
|
8019
|
+
class Time(RequiredAdapter[LoggingContextInfos.Time]):
|
8020
|
+
info_cls: ta.ClassVar[ta.Type[LoggingContextInfos.Time]] = LoggingContextInfos.Time
|
8021
|
+
|
8022
|
+
_record_attrs: ta.ClassVar[ta.Mapping[str, ta.Any]] = dict(
|
8023
|
+
# Time when the LogRecord was created. Set to `time.time_ns() / 1e9` for >=3.13.0b1, otherwise simply
|
8024
|
+
# `time.time()`.
|
8025
|
+
#
|
8026
|
+
# See:
|
8027
|
+
# - https://github.com/python/cpython/commit/1316692e8c7c1e1f3b6639e51804f9db5ed892ea
|
8028
|
+
# - https://github.com/python/cpython/commit/1500a23f33f5a6d052ff1ef6383d9839928b8ff1
|
8029
|
+
#
|
8030
|
+
created=float,
|
8031
|
+
|
8032
|
+
# Millisecond portion of the time when the LogRecord was created.
|
8033
|
+
msecs=float,
|
8034
|
+
|
8035
|
+
# Time in milliseconds when the LogRecord was created, relative to the time the logging module was loaded.
|
8036
|
+
relativeCreated=float,
|
8037
|
+
)
|
7918
8038
|
|
7919
|
-
|
7920
|
-
|
7921
|
-
|
8039
|
+
def _info_to_record(self, info: LoggingContextInfos.Time) -> ta.Mapping[str, ta.Any]:
|
8040
|
+
return dict(
|
8041
|
+
created=info.secs,
|
8042
|
+
msecs=info.msecs,
|
8043
|
+
relativeCreated=info.relative_secs,
|
8044
|
+
)
|
7922
8045
|
|
7923
|
-
|
8046
|
+
def record_to_info(self, rec: logging.LogRecord) -> LoggingContextInfos.Time:
|
8047
|
+
return LoggingContextInfos.Time.build(
|
8048
|
+
int(rec.created * 1e9),
|
8049
|
+
)
|
7924
8050
|
|
7925
|
-
|
7926
|
-
|
7927
|
-
|
7928
|
-
|
8051
|
+
class Exc(OptionalAdapter[LoggingContextInfos.Exc]):
|
8052
|
+
info_cls: ta.ClassVar[ta.Type[LoggingContextInfos.Exc]] = LoggingContextInfos.Exc
|
8053
|
+
|
8054
|
+
_record_attrs: ta.ClassVar[ta.Mapping[str, ta.Tuple[ta.Any, ta.Any]]] = dict(
|
8055
|
+
# Exception tuple (à la sys.exc_info) or, if no exception has occurred, None. Unmodified by ctor.
|
8056
|
+
exc_info=(ta.Optional[LoggingExcInfoTuple], None),
|
8057
|
+
|
8058
|
+
# Used to cache the traceback text. Simply set to None by ctor, later set by Formatter.format.
|
8059
|
+
exc_text=(ta.Optional[str], None),
|
8060
|
+
)
|
8061
|
+
|
8062
|
+
def _info_to_record(self, info: LoggingContextInfos.Exc) -> ta.Mapping[str, ta.Any]:
|
8063
|
+
return dict(
|
8064
|
+
exc_info=info.info_tuple,
|
8065
|
+
exc_text=None,
|
8066
|
+
)
|
8067
|
+
|
8068
|
+
def record_to_info(self, rec: logging.LogRecord) -> ta.Optional[LoggingContextInfos.Exc]:
|
8069
|
+
# FIXME:
|
8070
|
+
# error: Argument 1 to "build" of "Exc" has incompatible type
|
8071
|
+
# "tuple[type[BaseException], BaseException, TracebackType | None] | tuple[None, None, None] | None"; expected # noqa
|
8072
|
+
# "BaseException | tuple[type[BaseException], BaseException, TracebackType | None] | bool | None" [arg-type] # noqa
|
8073
|
+
return LoggingContextInfos.Exc.build(rec.exc_info) # type: ignore[arg-type]
|
8074
|
+
|
8075
|
+
class Caller(OptionalAdapter[LoggingContextInfos.Caller]):
|
8076
|
+
info_cls: ta.ClassVar[ta.Type[LoggingContextInfos.Caller]] = LoggingContextInfos.Caller
|
7929
8077
|
|
7930
|
-
|
8078
|
+
_UNKNOWN_PATH_NAME: ta.ClassVar[str] = '(unknown file)'
|
8079
|
+
_UNKNOWN_FUNC_NAME: ta.ClassVar[str] = '(unknown function)'
|
8080
|
+
|
8081
|
+
_STACK_INFO_PREFIX: ta.ClassVar[str] = 'Stack (most recent call last):\n'
|
8082
|
+
|
8083
|
+
_record_attrs: ta.ClassVar[ta.Mapping[str, ta.Tuple[ta.Any, ta.Any]]] = dict(
|
8084
|
+
# Full pathname of the source file where the logging call was issued (if available). Unmodified by ctor. May
|
8085
|
+
# default to "(unknown file)" by Logger.findCaller / Logger._log.
|
8086
|
+
pathname=(str, _UNKNOWN_PATH_NAME),
|
8087
|
+
|
8088
|
+
# Source line number where the logging call was issued (if available). Unmodified by ctor. May default to 0
|
8089
|
+
# y Logger.findCaller / Logger._log.
|
8090
|
+
lineno=(int, 0),
|
8091
|
+
|
8092
|
+
# Name of function containing the logging call. Set by ctor to `func` arg, unmodified. May default to
|
8093
|
+
# "(unknown function)" by Logger.findCaller / Logger._log.
|
8094
|
+
funcName=(str, _UNKNOWN_FUNC_NAME),
|
8095
|
+
|
8096
|
+
# Stack frame information (where available) from the bottom of the stack in the current thread, up to and
|
8097
|
+
# including the stack frame of the logging call which resulted in the creation of this record. Set by ctor
|
8098
|
+
# to `sinfo` arg, unmodified. Mostly set, if requested, by `Logger.findCaller`, to
|
8099
|
+
# `traceback.print_stack(f)`, but prepended with the literal "Stack (most recent call last):\n", and
|
8100
|
+
# stripped of exactly one trailing `\n` if present.
|
8101
|
+
stack_info=(ta.Optional[str], None),
|
8102
|
+
)
|
8103
|
+
|
8104
|
+
def _info_to_record(self, caller: LoggingContextInfos.Caller) -> ta.Mapping[str, ta.Any]:
|
8105
|
+
if (sinfo := caller.stack_info) is not None:
|
8106
|
+
stack_info: ta.Optional[str] = '\n'.join([
|
8107
|
+
self._STACK_INFO_PREFIX,
|
8108
|
+
sinfo[1:] if sinfo.endswith('\n') else sinfo,
|
8109
|
+
])
|
8110
|
+
else:
|
8111
|
+
stack_info = None
|
8112
|
+
|
8113
|
+
return dict(
|
8114
|
+
pathname=caller.file_path,
|
8115
|
+
|
8116
|
+
lineno=caller.line_no,
|
8117
|
+
funcName=caller.func_name,
|
8118
|
+
|
8119
|
+
stack_info=stack_info,
|
8120
|
+
)
|
8121
|
+
|
8122
|
+
def record_to_info(self, rec: logging.LogRecord) -> ta.Optional[LoggingContextInfos.Caller]:
|
8123
|
+
# FIXME: piecemeal?
|
8124
|
+
# FIXME: strip _STACK_INFO_PREFIX
|
8125
|
+
raise NotImplementedError
|
8126
|
+
|
8127
|
+
class SourceFile(Adapter[LoggingContextInfos.SourceFile]):
|
8128
|
+
info_cls: ta.ClassVar[ta.Type[LoggingContextInfos.SourceFile]] = LoggingContextInfos.SourceFile
|
8129
|
+
|
8130
|
+
_record_attrs: ta.ClassVar[ta.Mapping[str, ta.Any]] = dict(
|
8131
|
+
# Filename portion of pathname. Set to `os.path.basename(pathname)` if successful, otherwise defaults to
|
8132
|
+
# pathname.
|
8133
|
+
filename=str,
|
8134
|
+
|
8135
|
+
# Module (name portion of filename). Set to `os.path.splitext(filename)[0]`, otherwise defaults to
|
8136
|
+
# "Unknown module".
|
8137
|
+
module=str,
|
8138
|
+
)
|
8139
|
+
|
8140
|
+
_UNKNOWN_MODULE: ta.ClassVar[str] = 'Unknown module'
|
8141
|
+
|
8142
|
+
def context_to_record(self, ctx: LoggingContext) -> ta.Mapping[str, ta.Any]:
|
8143
|
+
if (info := ctx.get_info(LoggingContextInfos.SourceFile)) is not None:
|
8144
|
+
return dict(
|
8145
|
+
filename=info.file_name,
|
8146
|
+
module=info.module,
|
8147
|
+
)
|
8148
|
+
|
8149
|
+
if (caller := ctx.get_info(LoggingContextInfos.Caller)) is not None:
|
8150
|
+
return dict(
|
8151
|
+
filename=caller.file_path,
|
8152
|
+
module=self._UNKNOWN_MODULE,
|
8153
|
+
)
|
8154
|
+
|
8155
|
+
return dict(
|
8156
|
+
filename=LoggingContextInfoRecordAdapters.Caller._UNKNOWN_PATH_NAME, # noqa
|
8157
|
+
module=self._UNKNOWN_MODULE,
|
8158
|
+
)
|
8159
|
+
|
8160
|
+
def record_to_info(self, rec: logging.LogRecord) -> ta.Optional[LoggingContextInfos.SourceFile]:
|
8161
|
+
if not (
|
8162
|
+
rec.module is None or
|
8163
|
+
rec.module == self._UNKNOWN_MODULE
|
8164
|
+
):
|
8165
|
+
return LoggingContextInfos.SourceFile(
|
8166
|
+
file_name=rec.filename,
|
8167
|
+
module=rec.module, # FIXME: piecemeal?
|
8168
|
+
)
|
8169
|
+
|
8170
|
+
return None
|
8171
|
+
|
8172
|
+
class Thread(OptionalAdapter[LoggingContextInfos.Thread]):
|
8173
|
+
info_cls: ta.ClassVar[ta.Type[LoggingContextInfos.Thread]] = LoggingContextInfos.Thread
|
8174
|
+
|
8175
|
+
_record_attrs: ta.ClassVar[ta.Mapping[str, ta.Tuple[ta.Any, ta.Any]]] = dict(
|
8176
|
+
# Thread ID if available, and `logging.logThreads` is truthy.
|
8177
|
+
thread=(ta.Optional[int], None),
|
8178
|
+
|
8179
|
+
# Thread name if available, and `logging.logThreads` is truthy.
|
8180
|
+
threadName=(ta.Optional[str], None),
|
8181
|
+
)
|
8182
|
+
|
8183
|
+
def _info_to_record(self, info: LoggingContextInfos.Thread) -> ta.Mapping[str, ta.Any]:
|
8184
|
+
if logging.logThreads:
|
8185
|
+
return dict(
|
8186
|
+
thread=info.ident,
|
8187
|
+
threadName=info.name,
|
8188
|
+
)
|
8189
|
+
|
8190
|
+
return self.record_defaults
|
8191
|
+
|
8192
|
+
def record_to_info(self, rec: logging.LogRecord) -> ta.Optional[LoggingContextInfos.Thread]:
|
8193
|
+
if (
|
8194
|
+
(ident := rec.thread) is not None and
|
8195
|
+
(name := rec.threadName) is not None
|
8196
|
+
):
|
8197
|
+
return LoggingContextInfos.Thread(
|
8198
|
+
ident=ident,
|
8199
|
+
native_id=None,
|
8200
|
+
name=name,
|
8201
|
+
)
|
8202
|
+
|
8203
|
+
return None
|
8204
|
+
|
8205
|
+
class Process(OptionalAdapter[LoggingContextInfos.Process]):
|
8206
|
+
info_cls: ta.ClassVar[ta.Type[LoggingContextInfos.Process]] = LoggingContextInfos.Process
|
8207
|
+
|
8208
|
+
_record_attrs: ta.ClassVar[ta.Mapping[str, ta.Tuple[ta.Any, ta.Any]]] = dict(
|
8209
|
+
# Process ID if available - that is, if `hasattr(os, 'getpid')` - and `logging.logProcesses` is truthy,
|
8210
|
+
# otherwise None.
|
8211
|
+
process=(ta.Optional[int], None),
|
8212
|
+
)
|
8213
|
+
|
8214
|
+
def _info_to_record(self, info: LoggingContextInfos.Process) -> ta.Mapping[str, ta.Any]:
|
8215
|
+
if logging.logProcesses:
|
8216
|
+
return dict(
|
8217
|
+
process=info.pid,
|
8218
|
+
)
|
8219
|
+
|
8220
|
+
return self.record_defaults
|
8221
|
+
|
8222
|
+
def record_to_info(self, rec: logging.LogRecord) -> ta.Optional[LoggingContextInfos.Process]:
|
8223
|
+
if (
|
8224
|
+
(pid := rec.process) is not None
|
8225
|
+
):
|
8226
|
+
return LoggingContextInfos.Process(
|
8227
|
+
pid=pid,
|
8228
|
+
)
|
8229
|
+
|
8230
|
+
return None
|
8231
|
+
|
8232
|
+
class Multiprocessing(OptionalAdapter[LoggingContextInfos.Multiprocessing]):
|
8233
|
+
info_cls: ta.ClassVar[ta.Type[LoggingContextInfos.Multiprocessing]] = LoggingContextInfos.Multiprocessing
|
8234
|
+
|
8235
|
+
_record_attrs: ta.ClassVar[ta.Mapping[str, ta.Tuple[ta.Any, ta.Any]]] = dict(
|
8236
|
+
# Process name if available. Set to None if `logging.logMultiprocessing` is not truthy. Otherwise, set to
|
8237
|
+
# 'MainProcess', then `sys.modules.get('multiprocessing').current_process().name` if that works, otherwise
|
8238
|
+
# remains as 'MainProcess'.
|
8239
|
+
#
|
8240
|
+
# As noted by stdlib:
|
8241
|
+
#
|
8242
|
+
# Errors may occur if multiprocessing has not finished loading yet - e.g. if a custom import hook causes
|
8243
|
+
# third-party code to run when multiprocessing calls import. See issue 8200 for an example
|
8244
|
+
#
|
8245
|
+
processName=(ta.Optional[str], None),
|
8246
|
+
)
|
8247
|
+
|
8248
|
+
def _info_to_record(self, info: LoggingContextInfos.Multiprocessing) -> ta.Mapping[str, ta.Any]:
|
8249
|
+
if logging.logMultiprocessing:
|
8250
|
+
return dict(
|
8251
|
+
processName=info.process_name,
|
8252
|
+
)
|
8253
|
+
|
8254
|
+
return self.record_defaults
|
8255
|
+
|
8256
|
+
def record_to_info(self, rec: logging.LogRecord) -> ta.Optional[LoggingContextInfos.Multiprocessing]:
|
8257
|
+
if (
|
8258
|
+
(process_name := rec.processName) is not None
|
8259
|
+
):
|
8260
|
+
return LoggingContextInfos.Multiprocessing(
|
8261
|
+
process_name=process_name,
|
8262
|
+
)
|
8263
|
+
|
8264
|
+
return None
|
8265
|
+
|
8266
|
+
class AsyncioTask(OptionalAdapter[LoggingContextInfos.AsyncioTask]):
|
8267
|
+
info_cls: ta.ClassVar[ta.Type[LoggingContextInfos.AsyncioTask]] = LoggingContextInfos.AsyncioTask
|
8268
|
+
|
8269
|
+
_record_attrs: ta.ClassVar[ta.Mapping[str, ta.Union[ta.Any, ta.Tuple[ta.Any, ta.Any]]]] = dict(
|
8270
|
+
# Absent <3.12, otherwise asyncio.Task name if available, and `logging.logAsyncioTasks` is truthy. Set to
|
8271
|
+
# `sys.modules.get('asyncio').current_task().get_name()`, otherwise None.
|
8272
|
+
taskName=(ta.Optional[str], None),
|
8273
|
+
)
|
8274
|
+
|
8275
|
+
def _info_to_record(self, info: LoggingContextInfos.AsyncioTask) -> ta.Mapping[str, ta.Any]:
|
8276
|
+
if getattr(logging, 'logAsyncioTasks', None): # Absent <3.12
|
8277
|
+
return dict(
|
8278
|
+
taskName=info.name,
|
8279
|
+
)
|
8280
|
+
|
8281
|
+
return self.record_defaults
|
8282
|
+
|
8283
|
+
def record_to_info(self, rec: logging.LogRecord) -> ta.Optional[LoggingContextInfos.AsyncioTask]:
|
8284
|
+
if (
|
8285
|
+
(name := getattr(rec, 'taskName', None)) is not None
|
8286
|
+
):
|
8287
|
+
return LoggingContextInfos.AsyncioTask(
|
8288
|
+
name=name,
|
8289
|
+
)
|
8290
|
+
|
8291
|
+
return None
|
8292
|
+
|
8293
|
+
|
8294
|
+
_LOGGING_CONTEXT_INFO_RECORD_ADAPTERS_: ta.Sequence[LoggingContextInfoRecordAdapters.Adapter] = [ # noqa
|
8295
|
+
LoggingContextInfoRecordAdapters.Name(),
|
8296
|
+
LoggingContextInfoRecordAdapters.Level(),
|
8297
|
+
LoggingContextInfoRecordAdapters.Msg(),
|
8298
|
+
LoggingContextInfoRecordAdapters.Time(),
|
8299
|
+
LoggingContextInfoRecordAdapters.Exc(),
|
8300
|
+
LoggingContextInfoRecordAdapters.Caller(),
|
8301
|
+
LoggingContextInfoRecordAdapters.SourceFile(),
|
8302
|
+
LoggingContextInfoRecordAdapters.Thread(),
|
8303
|
+
LoggingContextInfoRecordAdapters.Process(),
|
8304
|
+
LoggingContextInfoRecordAdapters.Multiprocessing(),
|
8305
|
+
LoggingContextInfoRecordAdapters.AsyncioTask(),
|
8306
|
+
]
|
8307
|
+
|
8308
|
+
_LOGGING_CONTEXT_INFO_RECORD_ADAPTERS: ta.Mapping[ta.Type[LoggingContextInfo], LoggingContextInfoRecordAdapters.Adapter] = { # noqa
|
8309
|
+
ad.info_cls: ad for ad in _LOGGING_CONTEXT_INFO_RECORD_ADAPTERS_
|
8310
|
+
}
|
8311
|
+
|
8312
|
+
|
8313
|
+
##
|
8314
|
+
|
8315
|
+
|
8316
|
+
KNOWN_STD_LOGGING_RECORD_ATTR_SET: ta.FrozenSet[str] = frozenset(
|
8317
|
+
a for ad in _LOGGING_CONTEXT_INFO_RECORD_ADAPTERS.values() for a in ad.record_attrs
|
8318
|
+
)
|
7931
8319
|
|
7932
8320
|
|
7933
8321
|
# Formatter:
|
@@ -7951,14 +8339,17 @@ KNOWN_STD_LOGGING_FORMATTER_RECORD_ATTRS: ta.Dict[str, ta.Any] = dict(
|
|
7951
8339
|
KNOWN_STD_LOGGING_FORMATTER_RECORD_ATTR_SET: ta.FrozenSet[str] = frozenset(KNOWN_STD_LOGGING_FORMATTER_RECORD_ATTRS)
|
7952
8340
|
|
7953
8341
|
|
7954
|
-
##
|
7955
|
-
|
7956
|
-
|
7957
8342
|
class UnknownStdLoggingRecordAttrsWarning(LoggingSetupWarning):
|
7958
8343
|
pass
|
7959
8344
|
|
7960
8345
|
|
7961
8346
|
def _check_std_logging_record_attrs() -> None:
|
8347
|
+
if (
|
8348
|
+
len([a for ad in _LOGGING_CONTEXT_INFO_RECORD_ADAPTERS.values() for a in ad.record_attrs]) !=
|
8349
|
+
len(KNOWN_STD_LOGGING_RECORD_ATTR_SET)
|
8350
|
+
):
|
8351
|
+
raise RuntimeError('Duplicate LoggingContextInfoRecordAdapter record attrs')
|
8352
|
+
|
7962
8353
|
rec_dct = dict(logging.makeLogRecord({}).__dict__)
|
7963
8354
|
|
7964
8355
|
if (unk_rec_fields := frozenset(rec_dct) - KNOWN_STD_LOGGING_RECORD_ATTR_SET):
|
@@ -7977,116 +8368,20 @@ _check_std_logging_record_attrs()
|
|
7977
8368
|
|
7978
8369
|
|
7979
8370
|
class LoggingContextLogRecord(logging.LogRecord):
|
7980
|
-
|
7981
|
-
|
7982
|
-
|
7983
|
-
|
7984
|
-
|
7985
|
-
|
7986
|
-
|
7987
|
-
|
7988
|
-
|
7989
|
-
|
7990
|
-
|
7991
|
-
|
7992
|
-
|
7993
|
-
|
7994
|
-
# msg,
|
7995
|
-
# args,
|
7996
|
-
# exc_info,
|
7997
|
-
# func=None,
|
7998
|
-
# sinfo=None,
|
7999
|
-
# **kwargs,
|
8000
|
-
*,
|
8001
|
-
name: str,
|
8002
|
-
msg: str,
|
8003
|
-
args: ta.Union[tuple, dict],
|
8004
|
-
|
8005
|
-
_logging_context: LoggingContext,
|
8006
|
-
) -> None:
|
8007
|
-
ctx = _logging_context
|
8008
|
-
|
8009
|
-
self.name: str = name
|
8010
|
-
|
8011
|
-
self.msg: str = msg
|
8012
|
-
|
8013
|
-
# https://github.com/python/cpython/blob/e709361fc87d0d9ab9c58033a0a7f2fef0ad43d2/Lib/logging/__init__.py#L307
|
8014
|
-
if args and len(args) == 1 and isinstance(args[0], collections.abc.Mapping) and args[0]:
|
8015
|
-
args = args[0] # type: ignore[assignment]
|
8016
|
-
self.args: ta.Union[tuple, dict] = args
|
8017
|
-
|
8018
|
-
self.levelname: str = logging.getLevelName(ctx.level)
|
8019
|
-
self.levelno: int = ctx.level
|
8020
|
-
|
8021
|
-
if (caller := ctx.caller()) is not None:
|
8022
|
-
self.pathname: str = caller.file_path
|
8023
|
-
else:
|
8024
|
-
self.pathname = self._UNKNOWN_PATH_NAME
|
8025
|
-
|
8026
|
-
if (src_file := ctx.source_file()) is not None:
|
8027
|
-
self.filename: str = src_file.file_name
|
8028
|
-
self.module: str = src_file.module
|
8029
|
-
else:
|
8030
|
-
self.filename = self.pathname
|
8031
|
-
self.module = self._UNKNOWN_MODULE
|
8032
|
-
|
8033
|
-
self.exc_info: ta.Optional[LoggingExcInfoTuple] = ctx.exc_info_tuple
|
8034
|
-
self.exc_text: ta.Optional[str] = None
|
8035
|
-
|
8036
|
-
# If ctx.build_caller() was never called, we simply don't have a stack trace.
|
8037
|
-
if caller is not None:
|
8038
|
-
if (sinfo := caller.stack_info) is not None:
|
8039
|
-
self.stack_info: ta.Optional[str] = '\n'.join([
|
8040
|
-
self._STACK_INFO_PREFIX,
|
8041
|
-
sinfo[1:] if sinfo.endswith('\n') else sinfo,
|
8042
|
-
])
|
8043
|
-
else:
|
8044
|
-
self.stack_info = None
|
8045
|
-
|
8046
|
-
self.lineno: int = caller.line_no
|
8047
|
-
self.funcName: str = caller.name
|
8048
|
-
|
8049
|
-
else:
|
8050
|
-
self.stack_info = None
|
8051
|
-
|
8052
|
-
self.lineno = 0
|
8053
|
-
self.funcName = self._UNKNOWN_FUNC_NAME
|
8054
|
-
|
8055
|
-
times = ctx.times
|
8056
|
-
self.created: float = times.created
|
8057
|
-
self.msecs: float = times.msecs
|
8058
|
-
self.relativeCreated: float = times.relative_created
|
8059
|
-
|
8060
|
-
if logging.logThreads:
|
8061
|
-
thread = check.not_none(ctx.thread())
|
8062
|
-
self.thread: ta.Optional[int] = thread.ident
|
8063
|
-
self.threadName: ta.Optional[str] = thread.name
|
8064
|
-
else:
|
8065
|
-
self.thread = None
|
8066
|
-
self.threadName = None
|
8067
|
-
|
8068
|
-
if logging.logProcesses:
|
8069
|
-
process = check.not_none(ctx.process())
|
8070
|
-
self.process: ta.Optional[int] = process.pid
|
8071
|
-
else:
|
8072
|
-
self.process = None
|
8073
|
-
|
8074
|
-
if logging.logMultiprocessing:
|
8075
|
-
if (mp := ctx.multiprocessing()) is not None:
|
8076
|
-
self.processName: ta.Optional[str] = mp.process_name
|
8077
|
-
else:
|
8078
|
-
self.processName = None
|
8079
|
-
else:
|
8080
|
-
self.processName = None
|
8081
|
-
|
8082
|
-
# Absent <3.12
|
8083
|
-
if getattr(logging, 'logAsyncioTasks', None):
|
8084
|
-
if (at := ctx.asyncio_task()) is not None:
|
8085
|
-
self.taskName: ta.Optional[str] = at.name
|
8086
|
-
else:
|
8087
|
-
self.taskName = None
|
8088
|
-
else:
|
8089
|
-
self.taskName = None
|
8371
|
+
# LogRecord.__init__ args:
|
8372
|
+
# - name: str
|
8373
|
+
# - level: int
|
8374
|
+
# - pathname: str - Confusingly referred to as `fn` before the LogRecord ctor. May be empty or "(unknown file)".
|
8375
|
+
# - lineno: int - May be 0.
|
8376
|
+
# - msg: str
|
8377
|
+
# - args: tuple | dict | 1-tuple[dict]
|
8378
|
+
# - exc_info: LoggingExcInfoTuple | None
|
8379
|
+
# - func: str | None = None -> funcName
|
8380
|
+
# - sinfo: str | None = None -> stack_info
|
8381
|
+
|
8382
|
+
def __init__(self, *, _logging_context: LoggingContext) -> None: # noqa
|
8383
|
+
for ad in _LOGGING_CONTEXT_INFO_RECORD_ADAPTERS_:
|
8384
|
+
self.__dict__.update(ad.context_to_record(_logging_context))
|
8090
8385
|
|
8091
8386
|
|
8092
8387
|
########################################
|
@@ -8390,7 +8685,7 @@ class InterpResolver:
|
|
8390
8685
|
|
8391
8686
|
|
8392
8687
|
########################################
|
8393
|
-
# ../../../omlish/logs/std/
|
8688
|
+
# ../../../omlish/logs/std/loggers.py
|
8394
8689
|
|
8395
8690
|
|
8396
8691
|
##
|
@@ -8406,25 +8701,27 @@ class StdLogger(Logger):
|
|
8406
8701
|
def std(self) -> logging.Logger:
|
8407
8702
|
return self._std
|
8408
8703
|
|
8704
|
+
def is_enabled_for(self, level: LogLevel) -> bool:
|
8705
|
+
return self._std.isEnabledFor(level)
|
8706
|
+
|
8409
8707
|
def get_effective_level(self) -> LogLevel:
|
8410
8708
|
return self._std.getEffectiveLevel()
|
8411
8709
|
|
8412
8710
|
def _log(self, ctx: CaptureLoggingContext, msg: ta.Union[str, tuple, LoggingMsgFn], *args: ta.Any) -> None:
|
8413
|
-
if not self.is_enabled_for(ctx.level):
|
8711
|
+
if not self.is_enabled_for(ctx.must_get_info(LoggingContextInfos.Level).level):
|
8414
8712
|
return
|
8415
8713
|
|
8416
|
-
ctx.
|
8417
|
-
|
8418
|
-
ms, args = self._prepare_msg_args(msg, *args)
|
8419
|
-
|
8420
|
-
rec = LoggingContextLogRecord(
|
8714
|
+
ctx.set_basic(
|
8421
8715
|
name=self._std.name,
|
8422
|
-
msg=ms,
|
8423
|
-
args=args,
|
8424
8716
|
|
8425
|
-
|
8717
|
+
msg=msg,
|
8718
|
+
args=args,
|
8426
8719
|
)
|
8427
8720
|
|
8721
|
+
ctx.capture()
|
8722
|
+
|
8723
|
+
rec = LoggingContextLogRecord(_logging_context=ctx)
|
8724
|
+
|
8428
8725
|
self._std.handle(rec)
|
8429
8726
|
|
8430
8727
|
|