omdev 0.0.0.dev427__py3-none-any.whl → 0.0.0.dev429__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/.omlish-manifests.json +2 -2
- omdev/amalg/cli/main.py +1 -2
- omdev/cache/data/cache.py +2 -2
- omdev/cexts/_distutils/build_ext.py +5 -2
- omdev/cexts/_distutils/compilers/ccompiler.py +5 -2
- omdev/cexts/_distutils/compilers/options.py +3 -0
- omdev/cexts/_distutils/compilers/unixccompiler.py +6 -2
- omdev/cexts/_distutils/dir_util.py +6 -2
- omdev/cexts/_distutils/errors.py +3 -0
- omdev/cexts/_distutils/extension.py +3 -0
- omdev/cexts/_distutils/file_util.py +6 -2
- omdev/cexts/_distutils/modified.py +3 -0
- omdev/cexts/_distutils/spawn.py +6 -2
- omdev/cexts/_distutils/sysconfig.py +3 -0
- omdev/cexts/_distutils/util.py +6 -2
- omdev/cexts/_distutils/version.py +3 -0
- omdev/cexts/cmake.py +1 -2
- omdev/cexts/scan.py +1 -2
- omdev/ci/docker/dataserver.py +2 -2
- omdev/dataclasses/codegen.py +2 -2
- omdev/interp/inspect.py +2 -1
- omdev/interp/providers/system.py +2 -2
- omdev/interp/pyenv/provider.py +2 -2
- omdev/interp/uv/provider.py +3 -2
- omdev/interp/uv/uv.py +2 -2
- omdev/interp/venvs.py +2 -2
- omdev/precheck/lite.py +2 -2
- omdev/precheck/main.py +1 -2
- omdev/py/tools/mkrelimp.py +1 -2
- omdev/scripts/ci.py +4682 -3578
- omdev/scripts/interp.py +111 -9
- omdev/scripts/pyproject.py +1350 -144
- omdev/tools/git/cli.py +1 -2
- {omdev-0.0.0.dev427.dist-info → omdev-0.0.0.dev429.dist-info}/METADATA +2 -2
- {omdev-0.0.0.dev427.dist-info → omdev-0.0.0.dev429.dist-info}/RECORD +39 -39
- {omdev-0.0.0.dev427.dist-info → omdev-0.0.0.dev429.dist-info}/WHEEL +0 -0
- {omdev-0.0.0.dev427.dist-info → omdev-0.0.0.dev429.dist-info}/entry_points.txt +0 -0
- {omdev-0.0.0.dev427.dist-info → omdev-0.0.0.dev429.dist-info}/licenses/LICENSE +0 -0
- {omdev-0.0.0.dev427.dist-info → omdev-0.0.0.dev429.dist-info}/top_level.txt +0 -0
omdev/scripts/pyproject.py
CHANGED
@@ -5,7 +5,7 @@
|
|
5
5
|
# @omlish-generated
|
6
6
|
# @omlish-amalg-output ../pyproject/cli.py
|
7
7
|
# @omlish-git-diff-omit
|
8
|
-
# ruff: noqa: N802 TC003 UP006 UP007 UP036 UP043 UP045
|
8
|
+
# ruff: noqa: N802 TC003 UP006 UP007 UP036 UP043 UP045 UP046
|
9
9
|
"""
|
10
10
|
TODO:
|
11
11
|
- check / tests, src dir sets
|
@@ -65,6 +65,7 @@ import tarfile
|
|
65
65
|
import tempfile
|
66
66
|
import threading
|
67
67
|
import time
|
68
|
+
import traceback
|
68
69
|
import types
|
69
70
|
import typing as ta
|
70
71
|
import uuid
|
@@ -112,6 +113,9 @@ A0 = ta.TypeVar('A0')
|
|
112
113
|
A1 = ta.TypeVar('A1')
|
113
114
|
A2 = ta.TypeVar('A2')
|
114
115
|
|
116
|
+
# ../../omlish/logs/levels.py
|
117
|
+
LogLevel = int # ta.TypeAlias
|
118
|
+
|
115
119
|
# ../packaging/specifiers.py
|
116
120
|
UnparsedVersion = ta.Union['Version', str]
|
117
121
|
UnparsedVersionVar = ta.TypeVar('UnparsedVersionVar', bound=UnparsedVersion)
|
@@ -135,6 +139,14 @@ InjectorProviderFn = ta.Callable[['Injector'], ta.Any]
|
|
135
139
|
InjectorProviderFnMap = ta.Mapping['InjectorKey', 'InjectorProviderFn']
|
136
140
|
InjectorBindingOrBindings = ta.Union['InjectorBinding', 'InjectorBindings']
|
137
141
|
|
142
|
+
# ../../omlish/logs/contexts.py
|
143
|
+
LoggingExcInfoTuple = ta.Tuple[ta.Type[BaseException], BaseException, ta.Optional[types.TracebackType]] # ta.TypeAlias
|
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
|
149
|
+
|
138
150
|
# ../../omlish/subprocesses/base.py
|
139
151
|
SubprocessChannelOption = ta.Literal['pipe', 'stdout', 'devnull'] # ta.TypeAlias
|
140
152
|
|
@@ -2948,14 +2960,189 @@ def typing_annotations_attr() -> str:
|
|
2948
2960
|
|
2949
2961
|
|
2950
2962
|
########################################
|
2951
|
-
# ../../../omlish/logs/
|
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
|
+
########################################
|
3081
|
+
# ../../../omlish/logs/levels.py
|
2952
3082
|
|
2953
3083
|
|
2954
3084
|
##
|
2955
3085
|
|
2956
3086
|
|
2957
|
-
|
2958
|
-
|
3087
|
+
@ta.final
|
3088
|
+
class NamedLogLevel(int):
|
3089
|
+
# logging.getLevelNamesMapping (or, as that is unavailable <3.11, logging._nameToLevel) includes the deprecated
|
3090
|
+
# aliases.
|
3091
|
+
_NAMES_BY_INT: ta.ClassVar[ta.Mapping[LogLevel, str]] = dict(sorted(logging._levelToName.items(), key=lambda t: -t[0])) # noqa
|
3092
|
+
|
3093
|
+
_INTS_BY_NAME: ta.ClassVar[ta.Mapping[str, LogLevel]] = {v: k for k, v in _NAMES_BY_INT.items()}
|
3094
|
+
|
3095
|
+
_NAME_INT_PAIRS: ta.ClassVar[ta.Sequence[ta.Tuple[str, LogLevel]]] = list(_INTS_BY_NAME.items())
|
3096
|
+
|
3097
|
+
#
|
3098
|
+
|
3099
|
+
@property
|
3100
|
+
def exact_name(self) -> ta.Optional[str]:
|
3101
|
+
return self._NAMES_BY_INT.get(self)
|
3102
|
+
|
3103
|
+
_effective_name: ta.Optional[str]
|
3104
|
+
|
3105
|
+
@property
|
3106
|
+
def effective_name(self) -> ta.Optional[str]:
|
3107
|
+
try:
|
3108
|
+
return self._effective_name
|
3109
|
+
except AttributeError:
|
3110
|
+
pass
|
3111
|
+
|
3112
|
+
if (n := self.exact_name) is None:
|
3113
|
+
for n, i in self._NAME_INT_PAIRS: # noqa
|
3114
|
+
if self >= i:
|
3115
|
+
break
|
3116
|
+
else:
|
3117
|
+
n = None
|
3118
|
+
|
3119
|
+
self._effective_name = n
|
3120
|
+
return n
|
3121
|
+
|
3122
|
+
#
|
3123
|
+
|
3124
|
+
def __repr__(self) -> str:
|
3125
|
+
return f'{self.__class__.__name__}({int(self)})'
|
3126
|
+
|
3127
|
+
def __str__(self) -> str:
|
3128
|
+
return self.exact_name or f'{self.effective_name or "INVALID"}:{int(self)}'
|
3129
|
+
|
3130
|
+
#
|
3131
|
+
|
3132
|
+
CRITICAL: ta.ClassVar['NamedLogLevel']
|
3133
|
+
ERROR: ta.ClassVar['NamedLogLevel']
|
3134
|
+
WARNING: ta.ClassVar['NamedLogLevel']
|
3135
|
+
INFO: ta.ClassVar['NamedLogLevel']
|
3136
|
+
DEBUG: ta.ClassVar['NamedLogLevel']
|
3137
|
+
NOTSET: ta.ClassVar['NamedLogLevel']
|
3138
|
+
|
3139
|
+
|
3140
|
+
NamedLogLevel.CRITICAL = NamedLogLevel(logging.CRITICAL)
|
3141
|
+
NamedLogLevel.ERROR = NamedLogLevel(logging.ERROR)
|
3142
|
+
NamedLogLevel.WARNING = NamedLogLevel(logging.WARNING)
|
3143
|
+
NamedLogLevel.INFO = NamedLogLevel(logging.INFO)
|
3144
|
+
NamedLogLevel.DEBUG = NamedLogLevel(logging.DEBUG)
|
3145
|
+
NamedLogLevel.NOTSET = NamedLogLevel(logging.NOTSET)
|
2959
3146
|
|
2960
3147
|
|
2961
3148
|
########################################
|
@@ -3078,6 +3265,17 @@ class ProxyLoggingHandler(ProxyLoggingFilterer, logging.Handler):
|
|
3078
3265
|
self._underlying.handleError(record)
|
3079
3266
|
|
3080
3267
|
|
3268
|
+
########################################
|
3269
|
+
# ../../../omlish/logs/warnings.py
|
3270
|
+
|
3271
|
+
|
3272
|
+
##
|
3273
|
+
|
3274
|
+
|
3275
|
+
class LoggingSetupWarning(Warning):
|
3276
|
+
pass
|
3277
|
+
|
3278
|
+
|
3081
3279
|
########################################
|
3082
3280
|
# ../../cexts/magic.py
|
3083
3281
|
|
@@ -3832,90 +4030,6 @@ class SpecifierSet(BaseSpecifier):
|
|
3832
4030
|
return iter(filtered)
|
3833
4031
|
|
3834
4032
|
|
3835
|
-
########################################
|
3836
|
-
# ../reqs.py
|
3837
|
-
"""
|
3838
|
-
TODO:
|
3839
|
-
- embed pip._internal.req.parse_requirements, add additional env stuff? breaks compat with raw pip
|
3840
|
-
"""
|
3841
|
-
|
3842
|
-
|
3843
|
-
log = get_module_logger(globals()) # noqa
|
3844
|
-
|
3845
|
-
|
3846
|
-
##
|
3847
|
-
|
3848
|
-
|
3849
|
-
class RequirementsRewriter:
|
3850
|
-
def __init__(
|
3851
|
-
self,
|
3852
|
-
venv: ta.Optional[str] = None,
|
3853
|
-
) -> None:
|
3854
|
-
super().__init__()
|
3855
|
-
|
3856
|
-
self._venv = venv
|
3857
|
-
|
3858
|
-
@cached_nullary
|
3859
|
-
def _tmp_dir(self) -> str:
|
3860
|
-
return tempfile.mkdtemp('-omlish-reqs')
|
3861
|
-
|
3862
|
-
VENV_MAGIC = '# @omlish-venv'
|
3863
|
-
|
3864
|
-
def rewrite_file(self, in_file: str) -> str:
|
3865
|
-
with open(in_file) as f:
|
3866
|
-
src = f.read()
|
3867
|
-
|
3868
|
-
in_lines = src.splitlines(keepends=True)
|
3869
|
-
out_lines = []
|
3870
|
-
|
3871
|
-
for l in in_lines:
|
3872
|
-
if self.VENV_MAGIC in l:
|
3873
|
-
lp, _, rp = l.partition(self.VENV_MAGIC)
|
3874
|
-
rp = rp.partition('#')[0]
|
3875
|
-
omit = False
|
3876
|
-
for v in rp.split():
|
3877
|
-
if v[0] == '!':
|
3878
|
-
if self._venv is not None and self._venv == v[1:]:
|
3879
|
-
omit = True
|
3880
|
-
break
|
3881
|
-
else:
|
3882
|
-
raise NotImplementedError
|
3883
|
-
|
3884
|
-
if omit:
|
3885
|
-
out_lines.append('# OMITTED: ' + l)
|
3886
|
-
continue
|
3887
|
-
|
3888
|
-
out_req = self.rewrite(l.rstrip('\n'), for_file=True)
|
3889
|
-
out_lines.append(out_req + '\n')
|
3890
|
-
|
3891
|
-
out_file = os.path.join(self._tmp_dir(), os.path.basename(in_file))
|
3892
|
-
if os.path.exists(out_file):
|
3893
|
-
raise Exception(f'file exists: {out_file}')
|
3894
|
-
|
3895
|
-
with open(out_file, 'w') as f:
|
3896
|
-
f.write(''.join(out_lines))
|
3897
|
-
log.info('Rewrote requirements file %s to %s', in_file, out_file)
|
3898
|
-
return out_file
|
3899
|
-
|
3900
|
-
def rewrite(self, in_req: str, *, for_file: bool = False) -> str:
|
3901
|
-
if in_req.strip().startswith('-r'):
|
3902
|
-
l = in_req.strip()
|
3903
|
-
lp, _, rp = l.partition(' ')
|
3904
|
-
if lp == '-r':
|
3905
|
-
inc_in_file, _, rest = rp.partition(' ')
|
3906
|
-
else:
|
3907
|
-
inc_in_file, rest = lp[2:], rp
|
3908
|
-
|
3909
|
-
inc_out_file = self.rewrite_file(inc_in_file)
|
3910
|
-
if for_file:
|
3911
|
-
return ' '.join(['-r ', inc_out_file, rest])
|
3912
|
-
else:
|
3913
|
-
return '-r' + inc_out_file
|
3914
|
-
|
3915
|
-
else:
|
3916
|
-
return in_req
|
3917
|
-
|
3918
|
-
|
3919
4033
|
########################################
|
3920
4034
|
# ../../../omlish/argparse/cli.py
|
3921
4035
|
"""
|
@@ -5412,6 +5526,106 @@ class PredicateTimeout(Timeout):
|
|
5412
5526
|
return self()
|
5413
5527
|
|
5414
5528
|
|
5529
|
+
########################################
|
5530
|
+
# ../../../omlish/logs/callers.py
|
5531
|
+
|
5532
|
+
|
5533
|
+
##
|
5534
|
+
|
5535
|
+
|
5536
|
+
@logging_context_info
|
5537
|
+
@ta.final
|
5538
|
+
class LoggingCaller(ta.NamedTuple):
|
5539
|
+
file_path: str
|
5540
|
+
line_no: int
|
5541
|
+
name: str
|
5542
|
+
stack_info: ta.Optional[str]
|
5543
|
+
|
5544
|
+
@classmethod
|
5545
|
+
def is_internal_frame(cls, frame: types.FrameType) -> bool:
|
5546
|
+
file_path = os.path.normcase(frame.f_code.co_filename)
|
5547
|
+
|
5548
|
+
# Yes, really.
|
5549
|
+
# https://github.com/python/cpython/blob/e709361fc87d0d9ab9c58033a0a7f2fef0ad43d2/Lib/logging/__init__.py#L204
|
5550
|
+
# https://github.com/python/cpython/commit/5ca6d7469be53960843df39bb900e9c3359f127f
|
5551
|
+
if 'importlib' in file_path and '_bootstrap' in file_path:
|
5552
|
+
return True
|
5553
|
+
|
5554
|
+
return False
|
5555
|
+
|
5556
|
+
@classmethod
|
5557
|
+
def find_frame(cls, ofs: int = 0) -> ta.Optional[types.FrameType]:
|
5558
|
+
f: ta.Optional[types.FrameType] = sys._getframe(2 + ofs) # noqa
|
5559
|
+
|
5560
|
+
while f is not None:
|
5561
|
+
# NOTE: We don't check __file__ like stdlib since we may be running amalgamated - we rely on careful, manual
|
5562
|
+
# stack_offset management.
|
5563
|
+
if hasattr(f, 'f_code'):
|
5564
|
+
return f
|
5565
|
+
|
5566
|
+
f = f.f_back
|
5567
|
+
|
5568
|
+
return None
|
5569
|
+
|
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
|
+
return None
|
5579
|
+
|
5580
|
+
# https://github.com/python/cpython/blob/08e9794517063c8cd92c48714071b1d3c60b71bd/Lib/logging/__init__.py#L1616-L1623 # noqa
|
5581
|
+
sinfo = None
|
5582
|
+
if stack_info:
|
5583
|
+
sio = io.StringIO()
|
5584
|
+
traceback.print_stack(f, file=sio)
|
5585
|
+
sinfo = sio.getvalue()
|
5586
|
+
sio.close()
|
5587
|
+
if sinfo[-1] == '\n':
|
5588
|
+
sinfo = sinfo[:-1]
|
5589
|
+
|
5590
|
+
return cls(
|
5591
|
+
f.f_code.co_filename,
|
5592
|
+
f.f_lineno or 0,
|
5593
|
+
f.f_code.co_name,
|
5594
|
+
sinfo,
|
5595
|
+
)
|
5596
|
+
|
5597
|
+
|
5598
|
+
########################################
|
5599
|
+
# ../../../omlish/logs/protocols.py
|
5600
|
+
|
5601
|
+
|
5602
|
+
##
|
5603
|
+
|
5604
|
+
|
5605
|
+
class LoggerLike(ta.Protocol):
|
5606
|
+
"""Satisfied by both our Logger and stdlib logging.Logger."""
|
5607
|
+
|
5608
|
+
def isEnabledFor(self, level: LogLevel) -> bool: ... # noqa
|
5609
|
+
|
5610
|
+
def getEffectiveLevel(self) -> LogLevel: ... # noqa
|
5611
|
+
|
5612
|
+
#
|
5613
|
+
|
5614
|
+
def log(self, level: LogLevel, msg: str, /, *args: ta.Any, **kwargs: ta.Any) -> None: ... # noqa
|
5615
|
+
|
5616
|
+
def debug(self, msg: str, /, *args: ta.Any, **kwargs: ta.Any) -> None: ... # noqa
|
5617
|
+
|
5618
|
+
def info(self, msg: str, /, *args: ta.Any, **kwargs: ta.Any) -> None: ... # noqa
|
5619
|
+
|
5620
|
+
def warning(self, msg: str, /, *args: ta.Any, **kwargs: ta.Any) -> None: ... # noqa
|
5621
|
+
|
5622
|
+
def error(self, msg: str, /, *args: ta.Any, **kwargs: ta.Any) -> None: ... # noqa
|
5623
|
+
|
5624
|
+
def exception(self, msg: str, /, *args: ta.Any, **kwargs: ta.Any) -> None: ... # noqa
|
5625
|
+
|
5626
|
+
def critical(self, msg: str, /, *args: ta.Any, **kwargs: ta.Any) -> None: ... # noqa
|
5627
|
+
|
5628
|
+
|
5415
5629
|
########################################
|
5416
5630
|
# ../../../omlish/logs/std/json.py
|
5417
5631
|
"""
|
@@ -5470,17 +5684,102 @@ class JsonLoggingFormatter(logging.Formatter):
|
|
5470
5684
|
|
5471
5685
|
|
5472
5686
|
########################################
|
5473
|
-
#
|
5687
|
+
# ../../../omlish/logs/times.py
|
5474
5688
|
|
5475
5689
|
|
5476
5690
|
##
|
5477
5691
|
|
5478
5692
|
|
5479
|
-
|
5480
|
-
|
5481
|
-
|
5482
|
-
|
5483
|
-
|
5693
|
+
@logging_context_info
|
5694
|
+
@ta.final
|
5695
|
+
class LoggingTimeFields(ta.NamedTuple):
|
5696
|
+
"""Maps directly to stdlib `logging.LogRecord` fields, and must be kept in sync with it."""
|
5697
|
+
|
5698
|
+
created: float
|
5699
|
+
msecs: float
|
5700
|
+
relative_created: float
|
5701
|
+
|
5702
|
+
@classmethod
|
5703
|
+
def get_std_start_time_ns(cls) -> int:
|
5704
|
+
x: ta.Any = logging._startTime # type: ignore[attr-defined] # noqa
|
5705
|
+
|
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
|
+
|
5717
|
+
@classmethod
|
5718
|
+
def build(
|
5719
|
+
cls,
|
5720
|
+
time_ns: int,
|
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
|
5741
|
+
|
5742
|
+
return cls(
|
5743
|
+
created,
|
5744
|
+
msecs,
|
5745
|
+
relative_created,
|
5746
|
+
)
|
5747
|
+
|
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
|
+
])
|
5484
5783
|
|
5485
5784
|
INTERP_OPT_ATTRS_BY_GLYPH: ta.Mapping[str, str] = collections.OrderedDict(
|
5486
5785
|
(g, a) for a, g in INTERP_OPT_GLYPHS_BY_ATTR.items()
|
@@ -6674,6 +6973,263 @@ class InjectionApi:
|
|
6674
6973
|
inj = InjectionApi()
|
6675
6974
|
|
6676
6975
|
|
6976
|
+
########################################
|
6977
|
+
# ../../../omlish/logs/contexts.py
|
6978
|
+
|
6979
|
+
|
6980
|
+
##
|
6981
|
+
|
6982
|
+
|
6983
|
+
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
|
+
@abc.abstractmethod
|
6998
|
+
def times(self) -> LoggingTimeFields:
|
6999
|
+
raise NotImplementedError
|
7000
|
+
|
7001
|
+
#
|
7002
|
+
|
7003
|
+
@property
|
7004
|
+
@abc.abstractmethod
|
7005
|
+
def exc_info(self) -> ta.Optional[LoggingExcInfo]:
|
7006
|
+
raise NotImplementedError
|
7007
|
+
|
7008
|
+
@property
|
7009
|
+
@abc.abstractmethod
|
7010
|
+
def exc_info_tuple(self) -> ta.Optional[LoggingExcInfoTuple]:
|
7011
|
+
raise NotImplementedError
|
7012
|
+
|
7013
|
+
#
|
7014
|
+
|
7015
|
+
@abc.abstractmethod
|
7016
|
+
def caller(self) -> ta.Optional[LoggingCaller]:
|
7017
|
+
raise NotImplementedError
|
7018
|
+
|
7019
|
+
@abc.abstractmethod
|
7020
|
+
def source_file(self) -> ta.Optional[LoggingSourceFileInfo]:
|
7021
|
+
raise NotImplementedError
|
7022
|
+
|
7023
|
+
#
|
7024
|
+
|
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
|
+
class AlreadyCapturedError(Exception):
|
7047
|
+
pass
|
7048
|
+
|
7049
|
+
class NotCapturedError(Exception):
|
7050
|
+
pass
|
7051
|
+
|
7052
|
+
@abc.abstractmethod
|
7053
|
+
def capture(self) -> None:
|
7054
|
+
"""Must be cooperatively called only from the expected locations."""
|
7055
|
+
|
7056
|
+
raise NotImplementedError
|
7057
|
+
|
7058
|
+
|
7059
|
+
@ta.final
|
7060
|
+
class CaptureLoggingContextImpl(CaptureLoggingContext):
|
7061
|
+
@ta.final
|
7062
|
+
class NOT_SET: # noqa
|
7063
|
+
def __new__(cls, *args, **kwargs): # noqa
|
7064
|
+
raise TypeError
|
7065
|
+
|
7066
|
+
#
|
7067
|
+
|
7068
|
+
def __init__(
|
7069
|
+
self,
|
7070
|
+
level: LogLevel,
|
7071
|
+
*,
|
7072
|
+
time_ns: ta.Optional[int] = None,
|
7073
|
+
|
7074
|
+
exc_info: LoggingExcInfoArg = False,
|
7075
|
+
|
7076
|
+
caller: ta.Union[LoggingCaller, ta.Type[NOT_SET], None] = NOT_SET,
|
7077
|
+
stack_offset: int = 0,
|
7078
|
+
stack_info: bool = False,
|
7079
|
+
) -> None:
|
7080
|
+
self._level: NamedLogLevel = level if level.__class__ is NamedLogLevel else NamedLogLevel(level) # type: ignore[assignment] # noqa
|
7081
|
+
|
7082
|
+
#
|
7083
|
+
|
7084
|
+
if time_ns is None:
|
7085
|
+
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
|
+
|
7106
|
+
#
|
7107
|
+
|
7108
|
+
if caller is not CaptureLoggingContextImpl.NOT_SET:
|
7109
|
+
self._caller = caller # type: ignore[assignment]
|
7110
|
+
else:
|
7111
|
+
self._stack_offset = stack_offset
|
7112
|
+
self._stack_info = stack_info
|
7113
|
+
|
7114
|
+
##
|
7115
|
+
|
7116
|
+
@property
|
7117
|
+
def level(self) -> NamedLogLevel:
|
7118
|
+
return self._level
|
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
|
7137
|
+
|
7138
|
+
#
|
7139
|
+
|
7140
|
+
_exc_info: ta.Optional[LoggingExcInfo] = None
|
7141
|
+
_exc_info_tuple: ta.Optional[LoggingExcInfoTuple] = None
|
7142
|
+
|
7143
|
+
@property
|
7144
|
+
def exc_info(self) -> ta.Optional[LoggingExcInfo]:
|
7145
|
+
return self._exc_info
|
7146
|
+
|
7147
|
+
@property
|
7148
|
+
def exc_info_tuple(self) -> ta.Optional[LoggingExcInfoTuple]:
|
7149
|
+
return self._exc_info_tuple
|
7150
|
+
|
7151
|
+
##
|
7152
|
+
|
7153
|
+
_stack_offset: int
|
7154
|
+
_stack_info: bool
|
7155
|
+
|
7156
|
+
def inc_stack_offset(self, ofs: int = 1) -> 'CaptureLoggingContext':
|
7157
|
+
if hasattr(self, '_stack_offset'):
|
7158
|
+
self._stack_offset += ofs
|
7159
|
+
return self
|
7160
|
+
|
7161
|
+
_has_captured: bool = False
|
7162
|
+
|
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
|
+
def capture(self) -> None:
|
7172
|
+
if self._has_captured:
|
7173
|
+
raise CaptureLoggingContextImpl.AlreadyCapturedError
|
7174
|
+
self._has_captured = True
|
7175
|
+
|
7176
|
+
if not hasattr(self, '_caller'):
|
7177
|
+
self._caller = LoggingCaller.find(
|
7178
|
+
self._stack_offset + 1,
|
7179
|
+
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
|
7219
|
+
|
7220
|
+
def multiprocessing(self) -> ta.Optional[LoggingMultiprocessingInfo]:
|
7221
|
+
try:
|
7222
|
+
return self._multiprocessing
|
7223
|
+
except AttributeError:
|
7224
|
+
raise CaptureLoggingContext.NotCapturedError from None
|
7225
|
+
|
7226
|
+
def asyncio_task(self) -> ta.Optional[LoggingAsyncioTaskInfo]:
|
7227
|
+
try:
|
7228
|
+
return self._asyncio_task
|
7229
|
+
except AttributeError:
|
7230
|
+
raise CaptureLoggingContext.NotCapturedError from None
|
7231
|
+
|
7232
|
+
|
6677
7233
|
########################################
|
6678
7234
|
# ../../../omlish/logs/standard.py
|
6679
7235
|
"""
|
@@ -7018,68 +7574,584 @@ InterpProviders = ta.NewType('InterpProviders', ta.Sequence[InterpProvider])
|
|
7018
7574
|
|
7019
7575
|
|
7020
7576
|
########################################
|
7021
|
-
# ../../../omlish/
|
7577
|
+
# ../../../omlish/logs/base.py
|
7022
7578
|
|
7023
7579
|
|
7024
7580
|
##
|
7025
7581
|
|
7026
7582
|
|
7027
|
-
|
7028
|
-
|
7029
|
-
|
7030
|
-
|
7031
|
-
# - None
|
7583
|
+
class AnyLogger(Abstract, ta.Generic[T]):
|
7584
|
+
@ta.final
|
7585
|
+
def is_enabled_for(self, level: LogLevel) -> bool:
|
7586
|
+
return level >= self.get_effective_level()
|
7032
7587
|
|
7033
|
-
|
7034
|
-
|
7035
|
-
|
7036
|
-
'devnull': subprocess.DEVNULL,
|
7037
|
-
}
|
7588
|
+
@abc.abstractmethod
|
7589
|
+
def get_effective_level(self) -> LogLevel:
|
7590
|
+
raise NotImplementedError
|
7038
7591
|
|
7592
|
+
#
|
7039
7593
|
|
7040
|
-
|
7594
|
+
@ta.final
|
7595
|
+
def isEnabledFor(self, level: LogLevel) -> bool: # noqa
|
7596
|
+
return self.is_enabled_for(level)
|
7041
7597
|
|
7598
|
+
@ta.final
|
7599
|
+
def getEffectiveLevel(self) -> LogLevel: # noqa
|
7600
|
+
return self.get_effective_level()
|
7042
7601
|
|
7043
|
-
|
7044
|
-
@classmethod
|
7045
|
-
def from_std(cls, e: subprocess.CalledProcessError) -> 'VerboseCalledProcessError':
|
7046
|
-
return cls(
|
7047
|
-
e.returncode,
|
7048
|
-
e.cmd,
|
7049
|
-
output=e.output,
|
7050
|
-
stderr=e.stderr,
|
7051
|
-
)
|
7602
|
+
##
|
7052
7603
|
|
7053
|
-
|
7054
|
-
|
7055
|
-
|
7056
|
-
msg += f' Output: {self.output!r}'
|
7057
|
-
if self.stderr is not None:
|
7058
|
-
msg += f' Stderr: {self.stderr!r}'
|
7059
|
-
return msg
|
7604
|
+
@ta.overload
|
7605
|
+
def log(self, level: LogLevel, msg: str, *args: ta.Any, **kwargs: ta.Any) -> T:
|
7606
|
+
...
|
7060
7607
|
|
7608
|
+
@ta.overload
|
7609
|
+
def log(self, level: LogLevel, msg: ta.Tuple[ta.Any, ...], **kwargs: ta.Any) -> T:
|
7610
|
+
...
|
7061
7611
|
|
7062
|
-
|
7063
|
-
|
7612
|
+
@ta.overload
|
7613
|
+
def log(self, level: LogLevel, msg_fn: LoggingMsgFn, **kwargs: ta.Any) -> T:
|
7614
|
+
...
|
7064
7615
|
|
7065
|
-
|
7066
|
-
|
7067
|
-
|
7068
|
-
log: ta.Optional[logging.Logger] = None,
|
7069
|
-
try_exceptions: ta.Optional[ta.Tuple[ta.Type[Exception], ...]] = None,
|
7070
|
-
) -> None:
|
7071
|
-
super().__init__()
|
7616
|
+
@ta.final
|
7617
|
+
def log(self, level: LogLevel, *args, **kwargs):
|
7618
|
+
return self._log(CaptureLoggingContextImpl(level, stack_offset=1), *args, **kwargs)
|
7072
7619
|
|
7073
|
-
|
7074
|
-
self._try_exceptions = try_exceptions if try_exceptions is not None else self.DEFAULT_TRY_EXCEPTIONS
|
7620
|
+
#
|
7075
7621
|
|
7076
|
-
|
7077
|
-
|
7622
|
+
@ta.overload
|
7623
|
+
def debug(self, msg: str, *args: ta.Any, **kwargs: ta.Any) -> T:
|
7624
|
+
...
|
7625
|
+
|
7626
|
+
@ta.overload
|
7627
|
+
def debug(self, msg: ta.Tuple[ta.Any, ...], **kwargs: ta.Any) -> T:
|
7628
|
+
...
|
7629
|
+
|
7630
|
+
@ta.overload
|
7631
|
+
def debug(self, msg_fn: LoggingMsgFn, **kwargs: ta.Any) -> T:
|
7632
|
+
...
|
7633
|
+
|
7634
|
+
@ta.final
|
7635
|
+
def debug(self, *args, **kwargs):
|
7636
|
+
return self._log(CaptureLoggingContextImpl(NamedLogLevel.DEBUG, stack_offset=1), *args, **kwargs)
|
7078
7637
|
|
7079
7638
|
#
|
7080
7639
|
|
7081
|
-
|
7082
|
-
|
7640
|
+
@ta.overload
|
7641
|
+
def info(self, msg: str, *args: ta.Any, **kwargs: ta.Any) -> T:
|
7642
|
+
...
|
7643
|
+
|
7644
|
+
@ta.overload
|
7645
|
+
def info(self, msg: ta.Tuple[ta.Any, ...], **kwargs: ta.Any) -> T:
|
7646
|
+
...
|
7647
|
+
|
7648
|
+
@ta.overload
|
7649
|
+
def info(self, msg_fn: LoggingMsgFn, **kwargs: ta.Any) -> T:
|
7650
|
+
...
|
7651
|
+
|
7652
|
+
@ta.final
|
7653
|
+
def info(self, *args, **kwargs):
|
7654
|
+
return self._log(CaptureLoggingContextImpl(NamedLogLevel.INFO, stack_offset=1), *args, **kwargs)
|
7655
|
+
|
7656
|
+
#
|
7657
|
+
|
7658
|
+
@ta.overload
|
7659
|
+
def warning(self, msg: str, *args: ta.Any, **kwargs: ta.Any) -> T:
|
7660
|
+
...
|
7661
|
+
|
7662
|
+
@ta.overload
|
7663
|
+
def warning(self, msg: ta.Tuple[ta.Any, ...], **kwargs: ta.Any) -> T:
|
7664
|
+
...
|
7665
|
+
|
7666
|
+
@ta.overload
|
7667
|
+
def warning(self, msg_fn: LoggingMsgFn, **kwargs: ta.Any) -> T:
|
7668
|
+
...
|
7669
|
+
|
7670
|
+
@ta.final
|
7671
|
+
def warning(self, *args, **kwargs):
|
7672
|
+
return self._log(CaptureLoggingContextImpl(NamedLogLevel.WARNING, stack_offset=1), *args, **kwargs)
|
7673
|
+
|
7674
|
+
#
|
7675
|
+
|
7676
|
+
@ta.overload
|
7677
|
+
def error(self, msg: str, *args: ta.Any, **kwargs: ta.Any) -> T:
|
7678
|
+
...
|
7679
|
+
|
7680
|
+
@ta.overload
|
7681
|
+
def error(self, msg: ta.Tuple[ta.Any, ...], **kwargs: ta.Any) -> T:
|
7682
|
+
...
|
7683
|
+
|
7684
|
+
@ta.overload
|
7685
|
+
def error(self, msg_fn: LoggingMsgFn, **kwargs: ta.Any) -> T:
|
7686
|
+
...
|
7687
|
+
|
7688
|
+
@ta.final
|
7689
|
+
def error(self, *args, **kwargs):
|
7690
|
+
return self._log(CaptureLoggingContextImpl(NamedLogLevel.ERROR, stack_offset=1), *args, **kwargs)
|
7691
|
+
|
7692
|
+
#
|
7693
|
+
|
7694
|
+
@ta.overload
|
7695
|
+
def exception(self, msg: str, *args: ta.Any, exc_info: LoggingExcInfoArg = True, **kwargs: ta.Any) -> T:
|
7696
|
+
...
|
7697
|
+
|
7698
|
+
@ta.overload
|
7699
|
+
def exception(self, msg: ta.Tuple[ta.Any, ...], *, exc_info: LoggingExcInfoArg = True, **kwargs: ta.Any) -> T:
|
7700
|
+
...
|
7701
|
+
|
7702
|
+
@ta.overload
|
7703
|
+
def exception(self, msg_fn: LoggingMsgFn, *, exc_info: LoggingExcInfoArg = True, **kwargs: ta.Any) -> T:
|
7704
|
+
...
|
7705
|
+
|
7706
|
+
@ta.final
|
7707
|
+
def exception(self, *args, exc_info: LoggingExcInfoArg = True, **kwargs):
|
7708
|
+
return self._log(CaptureLoggingContextImpl(NamedLogLevel.ERROR, exc_info=exc_info, stack_offset=1), *args, **kwargs) # noqa
|
7709
|
+
|
7710
|
+
#
|
7711
|
+
|
7712
|
+
@ta.overload
|
7713
|
+
def critical(self, msg: str, *args: ta.Any, **kwargs: ta.Any) -> T:
|
7714
|
+
...
|
7715
|
+
|
7716
|
+
@ta.overload
|
7717
|
+
def critical(self, msg: ta.Tuple[ta.Any, ...], **kwargs: ta.Any) -> T:
|
7718
|
+
...
|
7719
|
+
|
7720
|
+
@ta.overload
|
7721
|
+
def critical(self, msg_fn: LoggingMsgFn, **kwargs: ta.Any) -> T:
|
7722
|
+
...
|
7723
|
+
|
7724
|
+
@ta.final
|
7725
|
+
def critical(self, *args, **kwargs):
|
7726
|
+
return self._log(CaptureLoggingContextImpl(NamedLogLevel.CRITICAL, stack_offset=1), *args, **kwargs)
|
7727
|
+
|
7728
|
+
##
|
7729
|
+
|
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
|
+
@abc.abstractmethod
|
7761
|
+
def _log(self, ctx: CaptureLoggingContext, msg: ta.Union[str, tuple, LoggingMsgFn], *args: ta.Any, **kwargs: ta.Any) -> T: # noqa
|
7762
|
+
raise NotImplementedError
|
7763
|
+
|
7764
|
+
|
7765
|
+
class Logger(AnyLogger[None], Abstract):
|
7766
|
+
@abc.abstractmethod
|
7767
|
+
def _log(self, ctx: CaptureLoggingContext, msg: ta.Union[str, tuple, LoggingMsgFn], *args: ta.Any, **kwargs: ta.Any) -> None: # noqa
|
7768
|
+
raise NotImplementedError
|
7769
|
+
|
7770
|
+
|
7771
|
+
class AsyncLogger(AnyLogger[ta.Awaitable[None]], Abstract):
|
7772
|
+
@abc.abstractmethod
|
7773
|
+
def _log(self, ctx: CaptureLoggingContext, msg: ta.Union[str, tuple, LoggingMsgFn], *args: ta.Any, **kwargs: ta.Any) -> ta.Awaitable[None]: # noqa
|
7774
|
+
raise NotImplementedError
|
7775
|
+
|
7776
|
+
|
7777
|
+
##
|
7778
|
+
|
7779
|
+
|
7780
|
+
class AnyNopLogger(AnyLogger[T], Abstract):
|
7781
|
+
@ta.final
|
7782
|
+
def get_effective_level(self) -> LogLevel:
|
7783
|
+
return 999
|
7784
|
+
|
7785
|
+
|
7786
|
+
@ta.final
|
7787
|
+
class NopLogger(AnyNopLogger[None], Logger):
|
7788
|
+
def _log(self, ctx: CaptureLoggingContext, msg: ta.Union[str, tuple, LoggingMsgFn], *args: ta.Any, **kwargs: ta.Any) -> None: # noqa
|
7789
|
+
pass
|
7790
|
+
|
7791
|
+
|
7792
|
+
@ta.final
|
7793
|
+
class AsyncNopLogger(AnyNopLogger[ta.Awaitable[None]], AsyncLogger):
|
7794
|
+
async def _log(self, ctx: CaptureLoggingContext, msg: ta.Union[str, tuple, LoggingMsgFn], *args: ta.Any, **kwargs: ta.Any) -> None: # noqa
|
7795
|
+
pass
|
7796
|
+
|
7797
|
+
|
7798
|
+
########################################
|
7799
|
+
# ../../../omlish/logs/std/records.py
|
7800
|
+
|
7801
|
+
|
7802
|
+
##
|
7803
|
+
|
7804
|
+
|
7805
|
+
# Ref:
|
7806
|
+
# - https://docs.python.org/3/library/logging.html#logrecord-attributes
|
7807
|
+
#
|
7808
|
+
# LogRecord:
|
7809
|
+
# - https://github.com/python/cpython/blob/39b2f82717a69dde7212bc39b673b0f55c99e6a3/Lib/logging/__init__.py#L276 (3.8)
|
7810
|
+
# - https://github.com/python/cpython/blob/f070f54c5f4a42c7c61d1d5d3b8f3b7203b4a0fb/Lib/logging/__init__.py#L286 (~3.14) # noqa
|
7811
|
+
#
|
7812
|
+
# LogRecord.__init__ args:
|
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,
|
7826
|
+
|
7827
|
+
# The format string passed in the original logging call. Merged with args to produce message, or an arbitrary object
|
7828
|
+
# (see Using arbitrary objects as messages). Unmodified by ctor.
|
7829
|
+
msg=str,
|
7830
|
+
|
7831
|
+
# The tuple of arguments merged into msg to produce message, or a dict whose values are used for the merge (when
|
7832
|
+
# there is only one argument, and it is a dictionary). Ctor will transform a 1-tuple containing a Mapping into just
|
7833
|
+
# the mapping, but is otherwise unmodified.
|
7834
|
+
args=ta.Union[tuple, dict],
|
7835
|
+
|
7836
|
+
#
|
7837
|
+
|
7838
|
+
# Text logging level for the message ('DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL'). Set to
|
7839
|
+
# `getLevelName(level)`.
|
7840
|
+
levelname=str,
|
7841
|
+
|
7842
|
+
# Numeric logging level for the message (DEBUG, INFO, WARNING, ERROR, CRITICAL). Unmodified by ctor.
|
7843
|
+
levelno=int,
|
7844
|
+
|
7845
|
+
#
|
7846
|
+
|
7847
|
+
# Full pathname of the source file where the logging call was issued (if available). Unmodified by ctor. May default
|
7848
|
+
# to "(unknown file)" by Logger.findCaller / Logger._log.
|
7849
|
+
pathname=str,
|
7850
|
+
|
7851
|
+
# Filename portion of pathname. Set to `os.path.basename(pathname)` if successful, otherwise defaults to pathname.
|
7852
|
+
filename=str,
|
7853
|
+
|
7854
|
+
# Module (name portion of filename). Set to `os.path.splitext(filename)[0]`, otherwise defaults to
|
7855
|
+
# "Unknown module".
|
7856
|
+
module=str,
|
7857
|
+
|
7858
|
+
#
|
7859
|
+
|
7860
|
+
# Exception tuple (à la sys.exc_info) or, if no exception has occurred, None. Unmodified by ctor.
|
7861
|
+
exc_info=ta.Optional[LoggingExcInfoTuple],
|
7862
|
+
|
7863
|
+
# Used to cache the traceback text. Simply set to None by ctor, later set by Formatter.format.
|
7864
|
+
exc_text=ta.Optional[str],
|
7865
|
+
|
7866
|
+
#
|
7867
|
+
|
7868
|
+
# Stack frame information (where available) from the bottom of the stack in the current thread, up to and including
|
7869
|
+
# the stack frame of the logging call which resulted in the creation of this record. Set by ctor to `sinfo` arg,
|
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],
|
7873
|
+
|
7874
|
+
# Source line number where the logging call was issued (if available). Unmodified by ctor. May default to 0 by
|
7875
|
+
# Logger.findCaller / Logger._log.
|
7876
|
+
lineno=int,
|
7877
|
+
|
7878
|
+
# Name of function containing the logging call. Set by ctor to `func` arg, unmodified. May default to
|
7879
|
+
# "(unknown function)" by Logger.findCaller / Logger._log.
|
7880
|
+
funcName=str,
|
7881
|
+
|
7882
|
+
#
|
7883
|
+
|
7884
|
+
# Time when the LogRecord was created. Set to `time.time_ns() / 1e9` for >=3.13.0b1, otherwise simply `time.time()`.
|
7885
|
+
#
|
7886
|
+
# See:
|
7887
|
+
# - https://github.com/python/cpython/commit/1316692e8c7c1e1f3b6639e51804f9db5ed892ea
|
7888
|
+
# - https://github.com/python/cpython/commit/1500a23f33f5a6d052ff1ef6383d9839928b8ff1
|
7889
|
+
#
|
7890
|
+
created=float,
|
7891
|
+
|
7892
|
+
# Millisecond portion of the time when the LogRecord was created.
|
7893
|
+
msecs=float,
|
7894
|
+
|
7895
|
+
# Time in milliseconds when the LogRecord was created, relative to the time the logging module was loaded.
|
7896
|
+
relativeCreated=float,
|
7897
|
+
|
7898
|
+
#
|
7899
|
+
|
7900
|
+
# Thread ID if available, and `logging.logThreads` is truthy.
|
7901
|
+
thread=ta.Optional[int],
|
7902
|
+
|
7903
|
+
# Thread name if available, and `logging.logThreads` is truthy.
|
7904
|
+
threadName=ta.Optional[str],
|
7905
|
+
|
7906
|
+
#
|
7907
|
+
|
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
|
+
#
|
7912
|
+
# As noted by stdlib:
|
7913
|
+
#
|
7914
|
+
# Errors may occur if multiprocessing has not finished loading yet - e.g. if a custom import hook causes
|
7915
|
+
# third-party code to run when multiprocessing calls import. See issue 8200 for an example
|
7916
|
+
#
|
7917
|
+
processName=ta.Optional[str],
|
7918
|
+
|
7919
|
+
# Process ID if available - that is, if `hasattr(os, 'getpid')` - and `logging.logProcesses` is truthy, otherwise
|
7920
|
+
# None.
|
7921
|
+
process=ta.Optional[int],
|
7922
|
+
|
7923
|
+
#
|
7924
|
+
|
7925
|
+
# Absent <3.12, otherwise asyncio.Task name if available, and `logging.logAsyncioTasks` is truthy. Set to
|
7926
|
+
# `sys.modules.get('asyncio').current_task().get_name()`, otherwise None.
|
7927
|
+
taskName=ta.Optional[str],
|
7928
|
+
)
|
7929
|
+
|
7930
|
+
KNOWN_STD_LOGGING_RECORD_ATTR_SET: ta.FrozenSet[str] = frozenset(KNOWN_STD_LOGGING_RECORD_ATTRS)
|
7931
|
+
|
7932
|
+
|
7933
|
+
# Formatter:
|
7934
|
+
# - https://github.com/python/cpython/blob/39b2f82717a69dde7212bc39b673b0f55c99e6a3/Lib/logging/__init__.py#L514 (3.8)
|
7935
|
+
# - https://github.com/python/cpython/blob/f070f54c5f4a42c7c61d1d5d3b8f3b7203b4a0fb/Lib/logging/__init__.py#L554 (~3.14) # noqa
|
7936
|
+
#
|
7937
|
+
KNOWN_STD_LOGGING_FORMATTER_RECORD_ATTRS: ta.Dict[str, ta.Any] = dict(
|
7938
|
+
# The logged message, computed as msg % args. Set to `record.getMessage()`.
|
7939
|
+
message=str,
|
7940
|
+
|
7941
|
+
# Human-readable time when the LogRecord was created. By default this is of the form '2003-07-08 16:49:45,896' (the
|
7942
|
+
# numbers after the comma are millisecond portion of the time). Set to `self.formatTime(record, self.datefmt)` if
|
7943
|
+
# `self.usesTime()`, otherwise unset.
|
7944
|
+
asctime=str,
|
7945
|
+
|
7946
|
+
# Used to cache the traceback text. If unset (falsey) on the record and `exc_info` is truthy, set to
|
7947
|
+
# `self.formatException(record.exc_info)` - otherwise unmodified.
|
7948
|
+
exc_text=ta.Optional[str],
|
7949
|
+
)
|
7950
|
+
|
7951
|
+
KNOWN_STD_LOGGING_FORMATTER_RECORD_ATTR_SET: ta.FrozenSet[str] = frozenset(KNOWN_STD_LOGGING_FORMATTER_RECORD_ATTRS)
|
7952
|
+
|
7953
|
+
|
7954
|
+
##
|
7955
|
+
|
7956
|
+
|
7957
|
+
class UnknownStdLoggingRecordAttrsWarning(LoggingSetupWarning):
|
7958
|
+
pass
|
7959
|
+
|
7960
|
+
|
7961
|
+
def _check_std_logging_record_attrs() -> None:
|
7962
|
+
rec_dct = dict(logging.makeLogRecord({}).__dict__)
|
7963
|
+
|
7964
|
+
if (unk_rec_fields := frozenset(rec_dct) - KNOWN_STD_LOGGING_RECORD_ATTR_SET):
|
7965
|
+
import warnings # noqa
|
7966
|
+
|
7967
|
+
warnings.warn(
|
7968
|
+
f'Unknown log record attrs detected: {sorted(unk_rec_fields)!r}',
|
7969
|
+
UnknownStdLoggingRecordAttrsWarning,
|
7970
|
+
)
|
7971
|
+
|
7972
|
+
|
7973
|
+
_check_std_logging_record_attrs()
|
7974
|
+
|
7975
|
+
|
7976
|
+
##
|
7977
|
+
|
7978
|
+
|
7979
|
+
class LoggingContextLogRecord(logging.LogRecord):
|
7980
|
+
_SHOULD_ADD_TASK_NAME: ta.ClassVar[bool] = sys.version_info >= (3, 12)
|
7981
|
+
|
7982
|
+
_UNKNOWN_PATH_NAME: ta.ClassVar[str] = '(unknown file)'
|
7983
|
+
_UNKNOWN_FUNC_NAME: ta.ClassVar[str] = '(unknown function)'
|
7984
|
+
_UNKNOWN_MODULE: ta.ClassVar[str] = 'Unknown module'
|
7985
|
+
|
7986
|
+
_STACK_INFO_PREFIX: ta.ClassVar[str] = 'Stack (most recent call last):\n'
|
7987
|
+
|
7988
|
+
def __init__( # noqa
|
7989
|
+
self,
|
7990
|
+
# name,
|
7991
|
+
# level,
|
7992
|
+
# pathname,
|
7993
|
+
# lineno,
|
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
|
8090
|
+
|
8091
|
+
|
8092
|
+
########################################
|
8093
|
+
# ../../../omlish/subprocesses/base.py
|
8094
|
+
|
8095
|
+
|
8096
|
+
##
|
8097
|
+
|
8098
|
+
|
8099
|
+
# Valid channel type kwarg values:
|
8100
|
+
# - A special flag negative int
|
8101
|
+
# - A positive fd int
|
8102
|
+
# - A file-like object
|
8103
|
+
# - None
|
8104
|
+
|
8105
|
+
SUBPROCESS_CHANNEL_OPTION_VALUES: ta.Mapping[SubprocessChannelOption, int] = {
|
8106
|
+
'pipe': subprocess.PIPE,
|
8107
|
+
'stdout': subprocess.STDOUT,
|
8108
|
+
'devnull': subprocess.DEVNULL,
|
8109
|
+
}
|
8110
|
+
|
8111
|
+
|
8112
|
+
##
|
8113
|
+
|
8114
|
+
|
8115
|
+
class VerboseCalledProcessError(subprocess.CalledProcessError):
|
8116
|
+
@classmethod
|
8117
|
+
def from_std(cls, e: subprocess.CalledProcessError) -> 'VerboseCalledProcessError':
|
8118
|
+
return cls(
|
8119
|
+
e.returncode,
|
8120
|
+
e.cmd,
|
8121
|
+
output=e.output,
|
8122
|
+
stderr=e.stderr,
|
8123
|
+
)
|
8124
|
+
|
8125
|
+
def __str__(self) -> str:
|
8126
|
+
msg = super().__str__()
|
8127
|
+
if self.output is not None:
|
8128
|
+
msg += f' Output: {self.output!r}'
|
8129
|
+
if self.stderr is not None:
|
8130
|
+
msg += f' Stderr: {self.stderr!r}'
|
8131
|
+
return msg
|
8132
|
+
|
8133
|
+
|
8134
|
+
class BaseSubprocesses(Abstract):
|
8135
|
+
DEFAULT_LOGGER: ta.ClassVar[ta.Optional[LoggerLike]] = None
|
8136
|
+
|
8137
|
+
def __init__(
|
8138
|
+
self,
|
8139
|
+
*,
|
8140
|
+
log: ta.Optional[LoggerLike] = None,
|
8141
|
+
try_exceptions: ta.Optional[ta.Tuple[ta.Type[Exception], ...]] = None,
|
8142
|
+
) -> None:
|
8143
|
+
super().__init__()
|
8144
|
+
|
8145
|
+
self._log = log if log is not None else self.DEFAULT_LOGGER
|
8146
|
+
self._try_exceptions = try_exceptions if try_exceptions is not None else self.DEFAULT_TRY_EXCEPTIONS
|
8147
|
+
|
8148
|
+
def set_logger(self, log: ta.Optional[LoggerLike]) -> None:
|
8149
|
+
self._log = log
|
8150
|
+
|
8151
|
+
#
|
8152
|
+
|
8153
|
+
def prepare_args(
|
8154
|
+
self,
|
7083
8155
|
*cmd: str,
|
7084
8156
|
env: ta.Optional[ta.Mapping[str, ta.Any]] = None,
|
7085
8157
|
extra_env: ta.Optional[ta.Mapping[str, ta.Any]] = None,
|
@@ -7317,6 +8389,45 @@ class InterpResolver:
|
|
7317
8389
|
print(f' {si}')
|
7318
8390
|
|
7319
8391
|
|
8392
|
+
########################################
|
8393
|
+
# ../../../omlish/logs/std/adapters.py
|
8394
|
+
|
8395
|
+
|
8396
|
+
##
|
8397
|
+
|
8398
|
+
|
8399
|
+
class StdLogger(Logger):
|
8400
|
+
def __init__(self, std: logging.Logger) -> None:
|
8401
|
+
super().__init__()
|
8402
|
+
|
8403
|
+
self._std = std
|
8404
|
+
|
8405
|
+
@property
|
8406
|
+
def std(self) -> logging.Logger:
|
8407
|
+
return self._std
|
8408
|
+
|
8409
|
+
def get_effective_level(self) -> LogLevel:
|
8410
|
+
return self._std.getEffectiveLevel()
|
8411
|
+
|
8412
|
+
def _log(self, ctx: CaptureLoggingContext, msg: ta.Union[str, tuple, LoggingMsgFn], *args: ta.Any) -> None:
|
8413
|
+
if not self.is_enabled_for(ctx.level):
|
8414
|
+
return
|
8415
|
+
|
8416
|
+
ctx.capture()
|
8417
|
+
|
8418
|
+
ms, args = self._prepare_msg_args(msg, *args)
|
8419
|
+
|
8420
|
+
rec = LoggingContextLogRecord(
|
8421
|
+
name=self._std.name,
|
8422
|
+
msg=ms,
|
8423
|
+
args=args,
|
8424
|
+
|
8425
|
+
_logging_context=ctx,
|
8426
|
+
)
|
8427
|
+
|
8428
|
+
self._std.handle(rec)
|
8429
|
+
|
8430
|
+
|
7320
8431
|
########################################
|
7321
8432
|
# ../../../omlish/subprocesses/asyncs.py
|
7322
8433
|
|
@@ -7628,7 +8739,7 @@ class AsyncioProcessCommunicator:
|
|
7628
8739
|
proc: asyncio.subprocess.Process,
|
7629
8740
|
loop: ta.Optional[ta.Any] = None,
|
7630
8741
|
*,
|
7631
|
-
log: ta.Optional[
|
8742
|
+
log: ta.Optional[LoggerLike] = None,
|
7632
8743
|
) -> None:
|
7633
8744
|
super().__init__()
|
7634
8745
|
|
@@ -7811,6 +8922,17 @@ class AsyncioSubprocesses(AbstractAsyncSubprocesses):
|
|
7811
8922
|
asyncio_subprocesses = AsyncioSubprocesses()
|
7812
8923
|
|
7813
8924
|
|
8925
|
+
########################################
|
8926
|
+
# ../../../omlish/logs/modules.py
|
8927
|
+
|
8928
|
+
|
8929
|
+
##
|
8930
|
+
|
8931
|
+
|
8932
|
+
def get_module_logger(mod_globals: ta.Mapping[str, ta.Any]) -> Logger:
|
8933
|
+
return StdLogger(logging.getLogger(mod_globals.get('__name__'))) # noqa
|
8934
|
+
|
8935
|
+
|
7814
8936
|
########################################
|
7815
8937
|
# ../../interp/inspect.py
|
7816
8938
|
|
@@ -7851,7 +8973,7 @@ class InterpInspector:
|
|
7851
8973
|
def __init__(
|
7852
8974
|
self,
|
7853
8975
|
*,
|
7854
|
-
log: ta.Optional[
|
8976
|
+
log: ta.Optional[LoggerLike] = None,
|
7855
8977
|
) -> None:
|
7856
8978
|
super().__init__()
|
7857
8979
|
|
@@ -8015,7 +9137,7 @@ class Uv:
|
|
8015
9137
|
self,
|
8016
9138
|
config: UvConfig = UvConfig(),
|
8017
9139
|
*,
|
8018
|
-
log: ta.Optional[
|
9140
|
+
log: ta.Optional[LoggerLike] = None,
|
8019
9141
|
) -> None:
|
8020
9142
|
super().__init__()
|
8021
9143
|
|
@@ -8182,6 +9304,90 @@ class GitRevisionAdder:
|
|
8182
9304
|
#
|
8183
9305
|
|
8184
9306
|
|
9307
|
+
########################################
|
9308
|
+
# ../reqs.py
|
9309
|
+
"""
|
9310
|
+
TODO:
|
9311
|
+
- embed pip._internal.req.parse_requirements, add additional env stuff? breaks compat with raw pip
|
9312
|
+
"""
|
9313
|
+
|
9314
|
+
|
9315
|
+
log = get_module_logger(globals()) # noqa
|
9316
|
+
|
9317
|
+
|
9318
|
+
##
|
9319
|
+
|
9320
|
+
|
9321
|
+
class RequirementsRewriter:
|
9322
|
+
def __init__(
|
9323
|
+
self,
|
9324
|
+
venv: ta.Optional[str] = None,
|
9325
|
+
) -> None:
|
9326
|
+
super().__init__()
|
9327
|
+
|
9328
|
+
self._venv = venv
|
9329
|
+
|
9330
|
+
@cached_nullary
|
9331
|
+
def _tmp_dir(self) -> str:
|
9332
|
+
return tempfile.mkdtemp('-omlish-reqs')
|
9333
|
+
|
9334
|
+
VENV_MAGIC = '# @omlish-venv'
|
9335
|
+
|
9336
|
+
def rewrite_file(self, in_file: str) -> str:
|
9337
|
+
with open(in_file) as f:
|
9338
|
+
src = f.read()
|
9339
|
+
|
9340
|
+
in_lines = src.splitlines(keepends=True)
|
9341
|
+
out_lines = []
|
9342
|
+
|
9343
|
+
for l in in_lines:
|
9344
|
+
if self.VENV_MAGIC in l:
|
9345
|
+
lp, _, rp = l.partition(self.VENV_MAGIC)
|
9346
|
+
rp = rp.partition('#')[0]
|
9347
|
+
omit = False
|
9348
|
+
for v in rp.split():
|
9349
|
+
if v[0] == '!':
|
9350
|
+
if self._venv is not None and self._venv == v[1:]:
|
9351
|
+
omit = True
|
9352
|
+
break
|
9353
|
+
else:
|
9354
|
+
raise NotImplementedError
|
9355
|
+
|
9356
|
+
if omit:
|
9357
|
+
out_lines.append('# OMITTED: ' + l)
|
9358
|
+
continue
|
9359
|
+
|
9360
|
+
out_req = self.rewrite(l.rstrip('\n'), for_file=True)
|
9361
|
+
out_lines.append(out_req + '\n')
|
9362
|
+
|
9363
|
+
out_file = os.path.join(self._tmp_dir(), os.path.basename(in_file))
|
9364
|
+
if os.path.exists(out_file):
|
9365
|
+
raise Exception(f'file exists: {out_file}')
|
9366
|
+
|
9367
|
+
with open(out_file, 'w') as f:
|
9368
|
+
f.write(''.join(out_lines))
|
9369
|
+
log.info('Rewrote requirements file %s to %s', in_file, out_file)
|
9370
|
+
return out_file
|
9371
|
+
|
9372
|
+
def rewrite(self, in_req: str, *, for_file: bool = False) -> str:
|
9373
|
+
if in_req.strip().startswith('-r'):
|
9374
|
+
l = in_req.strip()
|
9375
|
+
lp, _, rp = l.partition(' ')
|
9376
|
+
if lp == '-r':
|
9377
|
+
inc_in_file, _, rest = rp.partition(' ')
|
9378
|
+
else:
|
9379
|
+
inc_in_file, rest = lp[2:], rp
|
9380
|
+
|
9381
|
+
inc_out_file = self.rewrite_file(inc_in_file)
|
9382
|
+
if for_file:
|
9383
|
+
return ' '.join(['-r ', inc_out_file, rest])
|
9384
|
+
else:
|
9385
|
+
return '-r' + inc_out_file
|
9386
|
+
|
9387
|
+
else:
|
9388
|
+
return in_req
|
9389
|
+
|
9390
|
+
|
8185
9391
|
########################################
|
8186
9392
|
# ../../interp/providers/running.py
|
8187
9393
|
|
@@ -8231,7 +9437,7 @@ class SystemInterpProvider(InterpProvider):
|
|
8231
9437
|
options: Options = Options(),
|
8232
9438
|
*,
|
8233
9439
|
inspector: ta.Optional[InterpInspector] = None,
|
8234
|
-
log: ta.Optional[
|
9440
|
+
log: ta.Optional[LoggerLike] = None,
|
8235
9441
|
) -> None:
|
8236
9442
|
super().__init__()
|
8237
9443
|
|
@@ -8614,7 +9820,7 @@ class UvInterpProvider(InterpProvider):
|
|
8614
9820
|
*,
|
8615
9821
|
pyenv: Uv,
|
8616
9822
|
inspector: InterpInspector,
|
8617
|
-
log: ta.Optional[
|
9823
|
+
log: ta.Optional[LoggerLike] = None,
|
8618
9824
|
) -> None:
|
8619
9825
|
super().__init__()
|
8620
9826
|
|
@@ -9233,7 +10439,7 @@ class PyenvInterpProvider(InterpProvider):
|
|
9233
10439
|
*,
|
9234
10440
|
pyenv: Pyenv,
|
9235
10441
|
inspector: InterpInspector,
|
9236
|
-
log: ta.Optional[
|
10442
|
+
log: ta.Optional[LoggerLike] = None,
|
9237
10443
|
) -> None:
|
9238
10444
|
super().__init__()
|
9239
10445
|
|
@@ -9465,7 +10671,7 @@ class InterpVenv:
|
|
9465
10671
|
cfg: InterpVenvConfig,
|
9466
10672
|
*,
|
9467
10673
|
requirements_processor: ta.Optional[InterpVenvRequirementsProcessor] = None,
|
9468
|
-
log: ta.Optional[
|
10674
|
+
log: ta.Optional[LoggerLike] = None,
|
9469
10675
|
) -> None:
|
9470
10676
|
super().__init__()
|
9471
10677
|
|