logger-36 2025.14__py3-none-any.whl → 2025.16__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.
- logger_36/catalog/handler/console.py +0 -8
- logger_36/catalog/handler/file.py +0 -4
- logger_36/catalog/handler/generic.py +1 -1
- logger_36/type/handler.py +3 -2
- logger_36/type/logger.py +41 -14
- logger_36/type/loggers.py +27 -2
- logger_36/version.py +1 -1
- {logger_36-2025.14.dist-info → logger_36-2025.16.dist-info}/METADATA +1 -1
- {logger_36-2025.14.dist-info → logger_36-2025.16.dist-info}/RECORD +11 -13
- logger_36/api/exception.py +0 -56
- logger_36/extension/exception.py +0 -162
- {logger_36-2025.14.dist-info → logger_36-2025.16.dist-info}/WHEEL +0 -0
- {logger_36-2025.14.dist-info → logger_36-2025.16.dist-info}/top_level.txt +0 -0
@@ -37,14 +37,6 @@ class console_handler_t(base_t):
|
|
37
37
|
)
|
38
38
|
s.__stdout__.write(message[0] + "\n")
|
39
39
|
|
40
|
-
def LogAsIs(self, message: str, /) -> None:
|
41
|
-
""""""
|
42
|
-
s.__stdout__.write(message + "\n")
|
43
|
-
|
44
|
-
def DisplayRule(self, /, *, text: str | None = None, color: str = "black") -> None:
|
45
|
-
""""""
|
46
|
-
self.LogAsIs(RuleAsText(text, None))
|
47
|
-
|
48
40
|
|
49
41
|
"""
|
50
42
|
COPYRIGHT NOTICE
|
@@ -46,10 +46,6 @@ class file_handler_t(base_t):
|
|
46
46
|
self.stream.write(message + "\n")
|
47
47
|
self.stream.flush()
|
48
48
|
|
49
|
-
def DisplayRule(self, /, *, text: str | None = None, color: str = "black") -> None:
|
50
|
-
""""""
|
51
|
-
self.LogAsIs(RuleAsText(text, None))
|
52
|
-
|
53
49
|
|
54
50
|
"""
|
55
51
|
COPYRIGHT NOTICE
|
@@ -22,7 +22,7 @@ else:
|
|
22
22
|
EscapedForRich
|
23
23
|
) = DEFAULT_TERMINAL_THEME = None
|
24
24
|
|
25
|
-
from logger_36.task.format.rule import Rule, RuleAsText
|
25
|
+
from logger_36.task.format.rule import Rule, RuleAsText
|
26
26
|
from logger_36.type.handler import handler_t as base_t
|
27
27
|
|
28
28
|
LogAsIs_h = h.Callable[[str | h.Any], None]
|
logger_36/type/handler.py
CHANGED
@@ -13,6 +13,7 @@ from logger_36.config.message import FALLBACK_MESSAGE_WIDTH
|
|
13
13
|
from logger_36.constant.error import MEMORY_MEASURE_ERROR
|
14
14
|
from logger_36.constant.handler import HANDLER_KINDS
|
15
15
|
from logger_36.task.format.message import MessageFromRecord, MessageWithActualExpected
|
16
|
+
from logger_36.task.format.rule import RuleAsText
|
16
17
|
from logger_36.task.measure.chronos import TimeStamp
|
17
18
|
from logger_36.task.measure.memory import CanCheckUsage as CanCheckMemoryUsage
|
18
19
|
from logger_36.type.message import MessageFromRecord_h, RuleWithText_h
|
@@ -72,11 +73,11 @@ class _base_t:
|
|
72
73
|
See documentation of
|
73
74
|
logger_36.catalog.handler.generic.generic_handler_t.LogAsIs.
|
74
75
|
"""
|
75
|
-
|
76
|
+
s.__stdout__.write(message + "\n")
|
76
77
|
|
77
78
|
def DisplayRule(self, /, *, text: str | None = None, color: str = "black") -> None:
|
78
79
|
""""""
|
79
|
-
|
80
|
+
self.LogAsIs(RuleAsText(text, None))
|
80
81
|
|
81
82
|
|
82
83
|
class handler_t(l.Handler, _base_t):
|
logger_36/type/logger.py
CHANGED
@@ -8,6 +8,7 @@ import dataclasses as d
|
|
8
8
|
import logging as l
|
9
9
|
import sys as s
|
10
10
|
import textwrap as text
|
11
|
+
import threading as thrd
|
11
12
|
import traceback as tcbk
|
12
13
|
import types as t
|
13
14
|
import typing as h
|
@@ -43,7 +44,6 @@ from logger_36.constant.record import (
|
|
43
44
|
SHOW_W_RULE_ATTR,
|
44
45
|
STORE_MEMORY_ATTR,
|
45
46
|
)
|
46
|
-
from logger_36.extension.exception import OverrideExceptionFormat
|
47
47
|
from logger_36.task.format.message import MessageFromRecord, MessageWithActualExpected
|
48
48
|
from logger_36.task.format.rule import RuleAsText
|
49
49
|
from logger_36.task.measure.chronos import ElapsedTime
|
@@ -101,6 +101,7 @@ class logger_t(base_t):
|
|
101
101
|
intercepted_log_handles: dict[str, logger_handle_h] = d.field(
|
102
102
|
init=False, default_factory=dict
|
103
103
|
)
|
104
|
+
intercepts_exceptions: bool = d.field(init=False, default=False)
|
104
105
|
_on_hold: list[l.LogRecord] = d.field(init=False, default_factory=list)
|
105
106
|
_should_hold_messages: bool = d.field(init=False, default=True)
|
106
107
|
_should_activate_log_interceptions: bool = d.field(init=False, default=False)
|
@@ -109,6 +110,7 @@ class logger_t(base_t):
|
|
109
110
|
level_: d.InitVar[int] = l.NOTSET
|
110
111
|
activate_wrn_interceptions: d.InitVar[bool] = True
|
111
112
|
activate_log_interceptions: d.InitVar[bool] = True
|
113
|
+
activate_exc_interceptions: d.InitVar[bool] = True
|
112
114
|
|
113
115
|
@property
|
114
116
|
def intercepts_warnings(self) -> bool:
|
@@ -154,6 +156,7 @@ class logger_t(base_t):
|
|
154
156
|
level_: int,
|
155
157
|
activate_wrn_interceptions: bool,
|
156
158
|
activate_log_interceptions: bool,
|
159
|
+
activate_exc_interceptions: bool,
|
157
160
|
) -> None:
|
158
161
|
""""""
|
159
162
|
base_t.__init__(self, name_)
|
@@ -169,6 +172,8 @@ class logger_t(base_t):
|
|
169
172
|
self.ToggleWarningInterceptions(True)
|
170
173
|
if activate_log_interceptions:
|
171
174
|
self._should_activate_log_interceptions = True
|
175
|
+
if activate_exc_interceptions:
|
176
|
+
self.ToggleExceptionInterceptions(True)
|
172
177
|
|
173
178
|
if self.exit_on_error:
|
174
179
|
self.exit_on_critical = True
|
@@ -296,7 +301,6 @@ class logger_t(base_t):
|
|
296
301
|
|
297
302
|
def MakeMonochrome(self) -> None:
|
298
303
|
""""""
|
299
|
-
OverrideExceptionFormat()
|
300
304
|
self.AddHandler(console_handler_t)
|
301
305
|
|
302
306
|
def MakeRich(self, *, alternating_logs: int = 0) -> None:
|
@@ -304,7 +308,6 @@ class logger_t(base_t):
|
|
304
308
|
if MISSING_RICH_MESSAGE is not None:
|
305
309
|
s.__stderr__.write(MISSING_RICH_MESSAGE + "\n")
|
306
310
|
|
307
|
-
OverrideExceptionFormat()
|
308
311
|
if console_rich_handler_t is console_handler_t:
|
309
312
|
handler_kwargs = {}
|
310
313
|
else:
|
@@ -313,7 +316,6 @@ class logger_t(base_t):
|
|
313
316
|
|
314
317
|
def MakePermanent(self, path: str | path_t, /) -> None:
|
315
318
|
""""""
|
316
|
-
OverrideExceptionFormat()
|
317
319
|
self.AddHandler(file_handler_t, path=path)
|
318
320
|
|
319
321
|
def ResetEventCounts(self) -> None:
|
@@ -377,6 +379,37 @@ class logger_t(base_t):
|
|
377
379
|
self.intercepted_log_handles.clear()
|
378
380
|
self.info("Log Interception: OFF")
|
379
381
|
|
382
|
+
def ToggleExceptionInterceptions(self, state: bool, /) -> None:
|
383
|
+
""""""
|
384
|
+
if state:
|
385
|
+
if self.intercepts_exceptions:
|
386
|
+
return
|
387
|
+
|
388
|
+
s.excepthook = self.DealWithException
|
389
|
+
thrd.excepthook = self.DealWithExceptionInThread
|
390
|
+
self.intercepts_exceptions = True
|
391
|
+
self.info("Exception Interception: ON")
|
392
|
+
else:
|
393
|
+
if not self.intercepts_exceptions:
|
394
|
+
return
|
395
|
+
|
396
|
+
s.excepthook = s.__excepthook__
|
397
|
+
thrd.excepthook = thrd.__excepthook__
|
398
|
+
self.intercepts_exceptions = False
|
399
|
+
self.info("Exception Interception: OFF")
|
400
|
+
|
401
|
+
def DealWithException(self, _, exc_value, exc_traceback, /) -> None:
|
402
|
+
""""""
|
403
|
+
exception = exc_value.with_traceback(exc_traceback)
|
404
|
+
self.LogException(exception, level=l.CRITICAL)
|
405
|
+
s.exit(1)
|
406
|
+
|
407
|
+
def DealWithExceptionInThread(
|
408
|
+
self, exc_type, exc_value, exc_traceback, _, /
|
409
|
+
) -> None:
|
410
|
+
""""""
|
411
|
+
self.DealWithException(exc_type, exc_value, exc_traceback)
|
412
|
+
|
380
413
|
def AddHandler(
|
381
414
|
self,
|
382
415
|
handler_t: type[base_handler_t],
|
@@ -476,8 +509,8 @@ class logger_t(base_t):
|
|
476
509
|
# - Why it's not: "\n".join(lines)?
|
477
510
|
# - Why adding exception name here and not when removing caller?
|
478
511
|
formatted = "".join(lines)
|
479
|
-
message = f"{type(exception).__name__}
|
480
|
-
self.log(level, message)
|
512
|
+
message = f"Exception of type {type(exception).__name__}\n----\n{formatted}"
|
513
|
+
self.log(level, message, extra={HIDE_WHERE_ATTR: None})
|
481
514
|
|
482
515
|
def LogAsIs(self, message: str, /, *, indented: bool = False) -> None:
|
483
516
|
""""""
|
@@ -485,10 +518,7 @@ class logger_t(base_t):
|
|
485
518
|
message = text.indent(message, LINE_INDENT)
|
486
519
|
|
487
520
|
for handler in self.handlers:
|
488
|
-
|
489
|
-
self.info(message)
|
490
|
-
else:
|
491
|
-
LogAsIs(message)
|
521
|
+
handler.LogAsIs(message)
|
492
522
|
|
493
523
|
info_raw = LogAsIs # To follow the convention of the logging methods info, error...
|
494
524
|
|
@@ -497,10 +527,7 @@ class logger_t(base_t):
|
|
497
527
|
) -> None:
|
498
528
|
""""""
|
499
529
|
for handler in self.handlers:
|
500
|
-
|
501
|
-
self.info(RuleAsText(message, None))
|
502
|
-
else:
|
503
|
-
DisplayRule(text=message, color=color)
|
530
|
+
handler.DisplayRule(text=message, color=color)
|
504
531
|
|
505
532
|
def AddContextLevel(self, new_level: str, /) -> None:
|
506
533
|
""""""
|
logger_36/type/loggers.py
CHANGED
@@ -5,8 +5,10 @@ SEE COPYRIGHT NOTICE BELOW
|
|
5
5
|
"""
|
6
6
|
|
7
7
|
import dataclasses as d
|
8
|
+
import logging as l
|
8
9
|
import typing as h
|
9
10
|
|
11
|
+
from logger_36.constant.logger import LOGGER_NAME
|
10
12
|
from logger_36.type.logger import logger_t
|
11
13
|
|
12
14
|
|
@@ -14,9 +16,32 @@ from logger_36.type.logger import logger_t
|
|
14
16
|
class loggers_t(dict[h.Hashable, logger_t]):
|
15
17
|
active: logger_t | None = d.field(init=False, default=None)
|
16
18
|
|
17
|
-
def AddNew(
|
19
|
+
def AddNew(
|
20
|
+
self,
|
21
|
+
uid: h.Hashable,
|
22
|
+
/,
|
23
|
+
*,
|
24
|
+
name: str = LOGGER_NAME,
|
25
|
+
level: int = l.NOTSET,
|
26
|
+
should_record_messages: bool = False,
|
27
|
+
exit_on_error: bool = False,
|
28
|
+
exit_on_critical: bool = False,
|
29
|
+
activate_wrn_interceptions: bool = True,
|
30
|
+
activate_log_interceptions: bool = True,
|
31
|
+
activate_exc_interceptions: bool = True,
|
32
|
+
) -> None:
|
18
33
|
""""""
|
19
|
-
|
34
|
+
logger = logger_t(
|
35
|
+
should_record_messages=should_record_messages,
|
36
|
+
exit_on_error=exit_on_error,
|
37
|
+
exit_on_critical=exit_on_critical,
|
38
|
+
name_=name,
|
39
|
+
level_=level,
|
40
|
+
activate_wrn_interceptions=activate_wrn_interceptions,
|
41
|
+
activate_log_interceptions=activate_log_interceptions,
|
42
|
+
activate_exc_interceptions=activate_exc_interceptions,
|
43
|
+
)
|
44
|
+
self.Add(uid, logger)
|
20
45
|
|
21
46
|
def Add(self, uid: h.Hashable, logger: logger_t, /) -> None:
|
22
47
|
""""""
|
logger_36/version.py
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
logger_36/__init__.py,sha256=UhKxuQLS1Pfgt5H0K_7BaDAPejOUR8byD5BYRCnHQMQ,2655
|
2
|
-
logger_36/version.py,sha256=
|
2
|
+
logger_36/version.py,sha256=vxBUi_PLey0-7pBB4KEVJ1RP-m_hqLO7B8S6ifB0twk,2206
|
3
3
|
logger_36/api/content.py,sha256=clHYYUKa8n4qef6PVlUV4mFHRRf6fnm9wEd2fu9oagA,2381
|
4
|
-
logger_36/api/exception.py,sha256=QKIkNJA0N6FvVHLTApiH3ymhVQoSYU08t2RkyufQPIw,2291
|
5
4
|
logger_36/api/gpu.py,sha256=BOumedCAPWvCo7J-KJ3XE-jr5S0KSmgcFv_S4QKRPO8,2252
|
6
5
|
logger_36/api/memory.py,sha256=szJVk4UTXsbYv3B-W9LFttf1F3j86GXHsKgEUOsXKl4,2743
|
7
6
|
logger_36/api/storage.py,sha256=t83D7Ge0ka7FCHUM8xchLsO_TMu0Bcc2IcBzw_gjkSA,2300
|
@@ -10,10 +9,10 @@ logger_36/api/time.py,sha256=Uw1jQtY1njsRuIPRAXX44v4nPOo84MSBu_WK_YCRzQs,2324
|
|
10
9
|
logger_36/api/type.py,sha256=4m5fZGI6LOQvFakEStFv6HTP4FY9nyFpNNlK34rCfQw,2286
|
11
10
|
logger_36/catalog/config/console_rich.py,sha256=lAa5Ev5BhXvmQzfIt1FNihMNUQJFlXaIzNanAMdgtd0,2861
|
12
11
|
logger_36/catalog/config/optional.py,sha256=HaN6mbx7gHBBppNvUw1ckhYTOrlYqb-b_r0mzPcHPjM,2398
|
13
|
-
logger_36/catalog/handler/console.py,sha256=
|
12
|
+
logger_36/catalog/handler/console.py,sha256=Dc9Iyg7yLqUh3H_KD1B0oou5eh7tqGxZi9x45GOLTJA,3027
|
14
13
|
logger_36/catalog/handler/console_rich.py,sha256=U4hD8qF88dpDALKkeOvwnrJpUbUpG5egq1JfImU4pFg,7168
|
15
|
-
logger_36/catalog/handler/file.py,sha256=
|
16
|
-
logger_36/catalog/handler/generic.py,sha256=
|
14
|
+
logger_36/catalog/handler/file.py,sha256=h6goKVAPfrYRIM8ypdyTsZKlSaj_7O-GghQquf0-zL4,3279
|
15
|
+
logger_36/catalog/handler/generic.py,sha256=rubsfh6Bbs2CFbUF2Wb3VG4AGgRAgP1nZYEV7-ukVY0,8250
|
17
16
|
logger_36/catalog/logger/chronos.py,sha256=ocY13f98EfknU7wZCv0FS9Xb7pTNaWCPSusXFIEvEd4,2437
|
18
17
|
logger_36/catalog/logger/gpu.py,sha256=ybn7Q8exiqoigvNpzEhg0Zp027WogypuNJwfsQ1pRY4,3416
|
19
18
|
logger_36/catalog/logger/memory.py,sha256=CWhr2J4BqArJxzH6tS-ZThr-rYPAQGtuLn0pP7Iryfg,4685
|
@@ -33,7 +32,6 @@ logger_36/constant/message.py,sha256=Ys_CAyhENlT8Z3rr-AxO4hjdl1jLsKzVSPQ8wqLOCPQ
|
|
33
32
|
logger_36/constant/path.py,sha256=fKJn2vGj012BU5DFRetDFus_tKMty2q_WL0J2KrXdCo,2731
|
34
33
|
logger_36/constant/record.py,sha256=9Q28lVH_s0og4v74delgwIPAJ9G28I5rBM-brXcoY80,2308
|
35
34
|
logger_36/constant/system.py,sha256=G2mzBTxRXoJMxb53TnmBaceMJC_q3WonoCG7y6nC_R8,2430
|
36
|
-
logger_36/extension/exception.py,sha256=CPie_jbp_cPhYln0dECFplykmS7pUaHqiiuQ4M5lvho,5416
|
37
35
|
logger_36/extension/html_.py,sha256=J9EX8-Rotq9i8bZ9U-dIpXv5gKLLnLmWqdDy4XayT1Q,3868
|
38
36
|
logger_36/extension/line.py,sha256=3MJ3B5PXJn18RHxBUcWnNBLEYzb7VTcEAufn7ULdYfY,3143
|
39
37
|
logger_36/instance/logger.py,sha256=oTw5svRzKRJKvGrrZUtutJIOjp5UISft3fl0Ze7DOBE,2241
|
@@ -45,12 +43,12 @@ logger_36/task/format/message.py,sha256=5mR9CZaARy9q-JtIX68IyY-DKTepkxyRV7juByqB
|
|
45
43
|
logger_36/task/format/rule.py,sha256=CtR7d2X-pZFKdqG6Y2_3b5AMKg_J274Jq69kht0N6xs,2910
|
46
44
|
logger_36/task/measure/chronos.py,sha256=1kVhu6jZlNAtNWQQh8ZVuRwZIAC9gGz3_ul1tn0t4Yw,3055
|
47
45
|
logger_36/task/measure/memory.py,sha256=OjU5EYFH8SnzlCQKAoiXvauUlwQYOrH34jFXTVYF0jE,2517
|
48
|
-
logger_36/type/handler.py,sha256=
|
46
|
+
logger_36/type/handler.py,sha256=2Q3crkhIzMLyuT7pBtpmouXgKWbULdsYw8vxQZBCT2g,6637
|
49
47
|
logger_36/type/issue.py,sha256=2rGsFqaQJCbeml9xN08mN_nK79L8qscaS_0ws36Y0bI,3214
|
50
|
-
logger_36/type/logger.py,sha256=
|
51
|
-
logger_36/type/loggers.py,sha256=
|
48
|
+
logger_36/type/logger.py,sha256=86G05pa2_N9M1Vfck5NIBwn_LJhwf2W485Tc6sm5GSw,26256
|
49
|
+
logger_36/type/loggers.py,sha256=KLPoZ8UtQNhUw6MVu2pBcbSsIMKzgTaoxCulS1z2zPU,3748
|
52
50
|
logger_36/type/message.py,sha256=zKME5p87ynsXte_b5usXV3VHaj34Uezs9Gg_WVWfaeY,3063
|
53
|
-
logger_36-2025.
|
54
|
-
logger_36-2025.
|
55
|
-
logger_36-2025.
|
56
|
-
logger_36-2025.
|
51
|
+
logger_36-2025.16.dist-info/METADATA,sha256=S9Dh7TabMHK2y5K4psh0RvRiDHfcJiTjjYZKBGnvcCA,6506
|
52
|
+
logger_36-2025.16.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
53
|
+
logger_36-2025.16.dist-info/top_level.txt,sha256=sM95BTMWmslEEgR_1pzwZsOeSp8C_QBiu8ImbFr0XLc,10
|
54
|
+
logger_36-2025.16.dist-info/RECORD,,
|
logger_36/api/exception.py
DELETED
@@ -1,56 +0,0 @@
|
|
1
|
-
"""
|
2
|
-
Copyright CNRS/Inria/UniCA
|
3
|
-
Contributor(s): Eric Debreuve (eric.debreuve@cnrs.fr) since 2023
|
4
|
-
SEE COPYRIGHT NOTICE BELOW
|
5
|
-
"""
|
6
|
-
|
7
|
-
from logger_36.extension.exception import ( # noqa
|
8
|
-
OverrideExceptionFormat,
|
9
|
-
ResetExceptionFormat,
|
10
|
-
)
|
11
|
-
|
12
|
-
"""
|
13
|
-
COPYRIGHT NOTICE
|
14
|
-
|
15
|
-
This software is governed by the CeCILL license under French law and
|
16
|
-
abiding by the rules of distribution of free software. You can use,
|
17
|
-
modify and/ or redistribute the software under the terms of the CeCILL
|
18
|
-
license as circulated by CEA, CNRS and INRIA at the following URL
|
19
|
-
"http://www.cecill.info".
|
20
|
-
|
21
|
-
As a counterpart to the access to the source code and rights to copy,
|
22
|
-
modify and redistribute granted by the license, users are provided only
|
23
|
-
with a limited warranty and the software's author, the holder of the
|
24
|
-
economic rights, and the successive licensors have only limited
|
25
|
-
liability.
|
26
|
-
|
27
|
-
In this respect, the user's attention is drawn to the risks associated
|
28
|
-
with loading, using, modifying and/or developing or reproducing the
|
29
|
-
software by the user in light of its specific status of free software,
|
30
|
-
that may mean that it is complicated to manipulate, and that also
|
31
|
-
therefore means that it is reserved for developers and experienced
|
32
|
-
professionals having in-depth computer knowledge. Users are therefore
|
33
|
-
encouraged to load and test the software's suitability as regards their
|
34
|
-
requirements in conditions enabling the security of their systems and/or
|
35
|
-
data to be ensured and, more generally, to use and operate it in the
|
36
|
-
same conditions as regards security.
|
37
|
-
|
38
|
-
The fact that you are presently reading this means that you have had
|
39
|
-
knowledge of the CeCILL license and that you accept its terms.
|
40
|
-
|
41
|
-
SEE LICENCE NOTICE: file README-LICENCE-utf8.txt at project source root.
|
42
|
-
|
43
|
-
This software is being developed by Eric Debreuve, a CNRS employee and
|
44
|
-
member of team Morpheme.
|
45
|
-
Team Morpheme is a joint team between Inria, CNRS, and UniCA.
|
46
|
-
It is hosted by the Centre Inria d'Université Côte d'Azur, Laboratory
|
47
|
-
I3S, and Laboratory iBV.
|
48
|
-
|
49
|
-
CNRS: https://www.cnrs.fr/index.php/en
|
50
|
-
Inria: https://www.inria.fr/en/
|
51
|
-
UniCA: https://univ-cotedazur.eu/
|
52
|
-
Centre Inria d'Université Côte d'Azur: https://www.inria.fr/en/centre/sophia/
|
53
|
-
I3S: https://www.i3s.unice.fr/en/
|
54
|
-
iBV: http://ibv.unice.fr/
|
55
|
-
Team Morpheme: https://team.inria.fr/morpheme/
|
56
|
-
"""
|
logger_36/extension/exception.py
DELETED
@@ -1,162 +0,0 @@
|
|
1
|
-
"""
|
2
|
-
Copyright CNRS/Inria/UniCA
|
3
|
-
Contributor(s): Eric Debreuve (eric.debreuve@cnrs.fr) since 2023
|
4
|
-
SEE COPYRIGHT NOTICE BELOW
|
5
|
-
"""
|
6
|
-
|
7
|
-
import re as r
|
8
|
-
import sys as s
|
9
|
-
import tempfile as tmpf
|
10
|
-
import textwrap as text
|
11
|
-
import traceback as tcbk
|
12
|
-
import types as t
|
13
|
-
from pathlib import Path as path_t
|
14
|
-
|
15
|
-
from logger_36.catalog.config.optional import RICH_IS_AVAILABLE
|
16
|
-
from logger_36.constant.path import USER_FOLDER
|
17
|
-
|
18
|
-
_ORIGINAL_EXCEPTION_HANDLER = s.excepthook
|
19
|
-
_INDENTATION = " "
|
20
|
-
|
21
|
-
if RICH_IS_AVAILABLE:
|
22
|
-
from rich import print as ShowErrorMessage # noqa
|
23
|
-
|
24
|
-
TITLE_COLOR = "[red]"
|
25
|
-
FUNCTION_COLOR = "[cyan]"
|
26
|
-
REPORT_COLOR = "[red]"
|
27
|
-
MONOCHROME = "[/]"
|
28
|
-
OPTIONAL_NEWLINE = ""
|
29
|
-
else:
|
30
|
-
ShowErrorMessage = s.__stderr__.write
|
31
|
-
TITLE_COLOR = WHERE_COLOR = REPORT_COLOR = MONOCHROME = ""
|
32
|
-
OPTIONAL_NEWLINE = "\n"
|
33
|
-
|
34
|
-
|
35
|
-
def OverrideExceptionFormat() -> None:
|
36
|
-
""""""
|
37
|
-
s.excepthook = _HandleException
|
38
|
-
|
39
|
-
|
40
|
-
def ResetExceptionFormat() -> None:
|
41
|
-
""""""
|
42
|
-
s.excepthook = _ORIGINAL_EXCEPTION_HANDLER
|
43
|
-
|
44
|
-
|
45
|
-
def _HandleException(
|
46
|
-
stripe: type[Exception], exception: Exception, trace: t.TracebackType, /
|
47
|
-
) -> None:
|
48
|
-
""""""
|
49
|
-
while trace.tb_next is not None:
|
50
|
-
trace = trace.tb_next
|
51
|
-
frame = trace.tb_frame
|
52
|
-
code = frame.f_code
|
53
|
-
module = path_t(code.co_filename)
|
54
|
-
function = code.co_name
|
55
|
-
line_number = frame.f_lineno
|
56
|
-
line_content = module.read_text().splitlines()[line_number - 1].strip()
|
57
|
-
|
58
|
-
# Format module.
|
59
|
-
if module.is_relative_to(USER_FOLDER):
|
60
|
-
module = path_t("~") / module.relative_to(USER_FOLDER)
|
61
|
-
|
62
|
-
# Format line content.
|
63
|
-
if line_content.startswith("raise "):
|
64
|
-
# Do not display code of explicit exception raising.
|
65
|
-
line_content = None
|
66
|
-
|
67
|
-
# Find variables appearing in the line.
|
68
|
-
if line_content is None:
|
69
|
-
line_content = variables = ""
|
70
|
-
else:
|
71
|
-
all_variables = frame.f_locals
|
72
|
-
found_names = []
|
73
|
-
for match in r.finditer(r"[^\d\W]\w*", line_content):
|
74
|
-
name = match.group()
|
75
|
-
if name in all_variables:
|
76
|
-
found_names.append(name)
|
77
|
-
if found_names.__len__() > 0:
|
78
|
-
longest = max(map(len, found_names))
|
79
|
-
variables = map(
|
80
|
-
lambda _: f"{_:{longest}} = {all_variables[_]}", sorted(found_names)
|
81
|
-
)
|
82
|
-
variables = (
|
83
|
-
2 * _INDENTATION + f"\n{2 * _INDENTATION}".join(variables) + "\n"
|
84
|
-
)
|
85
|
-
else:
|
86
|
-
variables = ""
|
87
|
-
|
88
|
-
line_content = f"{_INDENTATION}{line_content}\n"
|
89
|
-
|
90
|
-
# Format message.
|
91
|
-
message = str(exception).strip()
|
92
|
-
if message.__len__() > 0:
|
93
|
-
if "\n" in message:
|
94
|
-
message = text.indent(message, 2 * _INDENTATION)[
|
95
|
-
(2 * _INDENTATION.__len__()) :
|
96
|
-
]
|
97
|
-
message = f"{_INDENTATION}{message[0].title()}{message[1:]}\n"
|
98
|
-
|
99
|
-
document = tmpf.NamedTemporaryFile(delete=False)
|
100
|
-
|
101
|
-
ShowErrorMessage(
|
102
|
-
f"{TITLE_COLOR}{stripe.__name__}{MONOCHROME}\n"
|
103
|
-
f"{_INDENTATION}{module}:{FUNCTION_COLOR}{function}{MONOCHROME}@{line_number}\n"
|
104
|
-
f"{line_content}"
|
105
|
-
f"{variables}"
|
106
|
-
f"{message}"
|
107
|
-
f"{_INDENTATION}{REPORT_COLOR}Full report at: file://{document.name}"
|
108
|
-
f"{MONOCHROME}{OPTIONAL_NEWLINE}"
|
109
|
-
)
|
110
|
-
|
111
|
-
lines = tcbk.format_exception(exception)
|
112
|
-
message = "".join(lines)
|
113
|
-
|
114
|
-
document.write(message.encode())
|
115
|
-
document.close()
|
116
|
-
|
117
|
-
|
118
|
-
"""
|
119
|
-
COPYRIGHT NOTICE
|
120
|
-
|
121
|
-
This software is governed by the CeCILL license under French law and
|
122
|
-
abiding by the rules of distribution of free software. You can use,
|
123
|
-
modify and/ or redistribute the software under the terms of the CeCILL
|
124
|
-
license as circulated by CEA, CNRS and INRIA at the following URL
|
125
|
-
"http://www.cecill.info".
|
126
|
-
|
127
|
-
As a counterpart to the access to the source code and rights to copy,
|
128
|
-
modify and redistribute granted by the license, users are provided only
|
129
|
-
with a limited warranty and the software's author, the holder of the
|
130
|
-
economic rights, and the successive licensors have only limited
|
131
|
-
liability.
|
132
|
-
|
133
|
-
In this respect, the user's attention is drawn to the risks associated
|
134
|
-
with loading, using, modifying and/or developing or reproducing the
|
135
|
-
software by the user in light of its specific status of free software,
|
136
|
-
that may mean that it is complicated to manipulate, and that also
|
137
|
-
therefore means that it is reserved for developers and experienced
|
138
|
-
professionals having in-depth computer knowledge. Users are therefore
|
139
|
-
encouraged to load and test the software's suitability as regards their
|
140
|
-
requirements in conditions enabling the security of their systems and/or
|
141
|
-
data to be ensured and, more generally, to use and operate it in the
|
142
|
-
same conditions as regards security.
|
143
|
-
|
144
|
-
The fact that you are presently reading this means that you have had
|
145
|
-
knowledge of the CeCILL license and that you accept its terms.
|
146
|
-
|
147
|
-
SEE LICENCE NOTICE: file README-LICENCE-utf8.txt at project source root.
|
148
|
-
|
149
|
-
This software is being developed by Eric Debreuve, a CNRS employee and
|
150
|
-
member of team Morpheme.
|
151
|
-
Team Morpheme is a joint team between Inria, CNRS, and UniCA.
|
152
|
-
It is hosted by the Centre Inria d'Université Côte d'Azur, Laboratory
|
153
|
-
I3S, and Laboratory iBV.
|
154
|
-
|
155
|
-
CNRS: https://www.cnrs.fr/index.php/en
|
156
|
-
Inria: https://www.inria.fr/en/
|
157
|
-
UniCA: https://univ-cotedazur.eu/
|
158
|
-
Centre Inria d'Université Côte d'Azur: https://www.inria.fr/en/centre/sophia/
|
159
|
-
I3S: https://www.i3s.unice.fr/en/
|
160
|
-
iBV: http://ibv.unice.fr/
|
161
|
-
Team Morpheme: https://team.inria.fr/morpheme/
|
162
|
-
"""
|
File without changes
|
File without changes
|