logger-36 2025.15__py3-none-any.whl → 2025.17__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 +1 -2
- logger_36/catalog/handler/console_rich.py +2 -14
- logger_36/catalog/handler/file.py +1 -4
- logger_36/catalog/handler/generic.py +2 -14
- logger_36/catalog/logger/memory.py +7 -5
- logger_36/constant/handler.py +0 -2
- logger_36/constant/path.py +2 -2
- logger_36/constant/record.py +1 -2
- logger_36/type/handler.py +6 -20
- logger_36/type/logger.py +68 -37
- logger_36/type/loggers.py +27 -2
- logger_36/version.py +1 -1
- {logger_36-2025.15.dist-info → logger_36-2025.17.dist-info}/METADATA +1 -1
- {logger_36-2025.15.dist-info → logger_36-2025.17.dist-info}/RECORD +16 -18
- logger_36/api/exception.py +0 -56
- logger_36/extension/exception.py +0 -162
- {logger_36-2025.15.dist-info → logger_36-2025.17.dist-info}/WHEEL +0 -0
- {logger_36-2025.15.dist-info → logger_36-2025.17.dist-info}/top_level.txt +0 -0
@@ -21,14 +21,13 @@ class console_handler_t(base_t):
|
|
21
21
|
/,
|
22
22
|
*,
|
23
23
|
name: str | None = None,
|
24
|
-
should_store_memory_usage: bool = False,
|
25
24
|
message_width: int = -1,
|
26
25
|
level: int = l.NOTSET,
|
27
26
|
formatter: l.Formatter | None = None,
|
28
27
|
**_,
|
29
28
|
) -> h.Self:
|
30
29
|
""""""
|
31
|
-
return cls(name,
|
30
|
+
return cls(name, message_width, level, formatter)
|
32
31
|
|
33
32
|
def emit(self, record: l.LogRecord, /) -> None:
|
34
33
|
""""""
|
@@ -55,7 +55,6 @@ class console_rich_handler_t(base_t):
|
|
55
55
|
def __init__(
|
56
56
|
self,
|
57
57
|
name: str | None,
|
58
|
-
should_store_memory_usage: bool,
|
59
58
|
message_width: int,
|
60
59
|
level: int,
|
61
60
|
formatter: l.Formatter | None,
|
@@ -67,15 +66,7 @@ class console_rich_handler_t(base_t):
|
|
67
66
|
|
68
67
|
assert alternating_logs in (0, 1, 2)
|
69
68
|
|
70
|
-
base_t.__init__(
|
71
|
-
self,
|
72
|
-
name,
|
73
|
-
should_store_memory_usage,
|
74
|
-
message_width,
|
75
|
-
level,
|
76
|
-
formatter,
|
77
|
-
kwargs,
|
78
|
-
)
|
69
|
+
base_t.__init__(self, name, message_width, level, formatter, kwargs)
|
79
70
|
|
80
71
|
self.console = None # console_t | None.
|
81
72
|
self.alternating_logs = alternating_logs
|
@@ -105,16 +96,13 @@ class console_rich_handler_t(base_t):
|
|
105
96
|
/,
|
106
97
|
*,
|
107
98
|
name: str | None = None,
|
108
|
-
should_store_memory_usage: bool = False,
|
109
99
|
message_width: int = -1,
|
110
100
|
level: int = l.NOTSET,
|
111
101
|
formatter: l.Formatter | None = None,
|
112
102
|
**kwargs,
|
113
103
|
) -> h.Self:
|
114
104
|
""""""
|
115
|
-
return cls(
|
116
|
-
name, should_store_memory_usage, message_width, level, formatter, kwargs
|
117
|
-
)
|
105
|
+
return cls(name, message_width, level, formatter, kwargs)
|
118
106
|
|
119
107
|
def emit(self, record: l.LogRecord, /) -> None:
|
120
108
|
""""""
|
@@ -21,7 +21,6 @@ class file_handler_t(base_t):
|
|
21
21
|
/,
|
22
22
|
*,
|
23
23
|
name: str | None = None,
|
24
|
-
should_store_memory_usage: bool = False,
|
25
24
|
message_width: int = -1,
|
26
25
|
level: int = l.NOTSET,
|
27
26
|
formatter: l.Formatter | None = None,
|
@@ -29,9 +28,7 @@ class file_handler_t(base_t):
|
|
29
28
|
**_,
|
30
29
|
) -> h.Self:
|
31
30
|
""""""
|
32
|
-
return cls(
|
33
|
-
name, should_store_memory_usage, message_width, level, formatter, path
|
34
|
-
)
|
31
|
+
return cls(name, message_width, level, formatter, path)
|
35
32
|
|
36
33
|
def emit(self, record: l.LogRecord, /) -> None:
|
37
34
|
""""""
|
@@ -56,7 +56,6 @@ class generic_handler_t(base_t):
|
|
56
56
|
def __init__(
|
57
57
|
self,
|
58
58
|
name: str | None,
|
59
|
-
should_store_memory_usage: bool,
|
60
59
|
message_width: int,
|
61
60
|
level: int,
|
62
61
|
formatter: l.Formatter | None,
|
@@ -69,15 +68,7 @@ class generic_handler_t(base_t):
|
|
69
68
|
|
70
69
|
assert alternating_logs in (0, 1, 2)
|
71
70
|
|
72
|
-
base_t.__init__(
|
73
|
-
self,
|
74
|
-
name,
|
75
|
-
should_store_memory_usage,
|
76
|
-
message_width,
|
77
|
-
level,
|
78
|
-
formatter,
|
79
|
-
kwargs,
|
80
|
-
)
|
71
|
+
base_t.__init__(self, name, message_width, level, formatter, kwargs)
|
81
72
|
|
82
73
|
self.LogAsIs = LogAsIs
|
83
74
|
self.DisplayRule = None # DisplayRule_p | None.
|
@@ -105,16 +96,13 @@ class generic_handler_t(base_t):
|
|
105
96
|
/,
|
106
97
|
*,
|
107
98
|
name: str | None = None,
|
108
|
-
should_store_memory_usage: bool = False,
|
109
99
|
message_width: int = -1,
|
110
100
|
level: int = l.NOTSET,
|
111
101
|
formatter: l.Formatter | None = None,
|
112
102
|
**kwargs,
|
113
103
|
) -> h.Self:
|
114
104
|
""""""
|
115
|
-
return cls(
|
116
|
-
name, should_store_memory_usage, message_width, level, formatter, kwargs
|
117
|
-
)
|
105
|
+
return cls(name, message_width, level, formatter, kwargs)
|
118
106
|
|
119
107
|
def emit(self, record: l.LogRecord, /) -> None:
|
120
108
|
""""""
|
@@ -21,7 +21,7 @@ def LogMemoryUsages(
|
|
21
21
|
logger: logger_t = L,
|
22
22
|
) -> None:
|
23
23
|
""""""
|
24
|
-
if not logger.
|
24
|
+
if (not hasattr(logger, "memory_usages")) or (logger.memory_usages.__len__() == 0):
|
25
25
|
return
|
26
26
|
|
27
27
|
where_s, usages = zip(*logger.memory_usages)
|
@@ -76,10 +76,12 @@ def LogMaximumMemoryUsage(
|
|
76
76
|
"""
|
77
77
|
unit: b or None=bytes, k=kilo, m=mega, g=giga, a=auto
|
78
78
|
"""
|
79
|
-
if logger.
|
80
|
-
|
81
|
-
|
82
|
-
|
79
|
+
if (not hasattr(logger, "memory_usages")) or (logger.memory_usages.__len__() == 0):
|
80
|
+
return
|
81
|
+
|
82
|
+
where, max_usage = logger.max_memory_usage_full
|
83
|
+
value, unit = FormattedUsage(max_usage, unit=unit, decimals=decimals)
|
84
|
+
logger.info(f"Max. Memory Usage: {value}{unit} near {where}")
|
83
85
|
|
84
86
|
|
85
87
|
"""
|
logger_36/constant/handler.py
CHANGED
logger_36/constant/path.py
CHANGED
@@ -4,13 +4,13 @@ Contributor(s): Eric Debreuve (eric.debreuve@cnrs.fr) since 2023
|
|
4
4
|
SEE COPYRIGHT NOTICE BELOW
|
5
5
|
"""
|
6
6
|
|
7
|
-
import inspect as
|
7
|
+
import inspect as e
|
8
8
|
import tempfile as tmps
|
9
9
|
from pathlib import Path as path_t
|
10
10
|
|
11
11
|
USER_FOLDER = path_t.home()
|
12
12
|
|
13
|
-
frame =
|
13
|
+
frame = e.stack(context=0)[-1] # -1=root caller.
|
14
14
|
if path_t(frame.filename).exists():
|
15
15
|
PROJECT_FILE = path_t(frame.filename)
|
16
16
|
if PROJECT_FILE.is_relative_to(USER_FOLDER):
|
logger_36/constant/record.py
CHANGED
logger_36/type/handler.py
CHANGED
@@ -10,26 +10,22 @@ import typing as h
|
|
10
10
|
from pathlib import Path as path_t
|
11
11
|
|
12
12
|
from logger_36.config.message import FALLBACK_MESSAGE_WIDTH
|
13
|
-
from logger_36.constant.error import MEMORY_MEASURE_ERROR
|
14
13
|
from logger_36.constant.handler import HANDLER_KINDS
|
15
14
|
from logger_36.task.format.message import MessageFromRecord, MessageWithActualExpected
|
16
15
|
from logger_36.task.format.rule import RuleAsText
|
17
16
|
from logger_36.task.measure.chronos import TimeStamp
|
18
|
-
from logger_36.task.measure.memory import CanCheckUsage as CanCheckMemoryUsage
|
19
17
|
from logger_36.type.message import MessageFromRecord_h, RuleWithText_h
|
20
18
|
|
21
|
-
_MEMORY_MEASURE_ERROR = MEMORY_MEASURE_ERROR
|
22
|
-
|
23
19
|
|
24
20
|
class _base_t:
|
25
21
|
kind: h.ClassVar[str] = "" # See logger_36.constant.handler.handler_codes_h.
|
26
22
|
|
27
|
-
def __init__(
|
28
|
-
self, name: str | None, should_store_memory_usage: bool, message_width: int
|
29
|
-
) -> None:
|
23
|
+
def __init__(self, name: str | None, message_width: int) -> None:
|
30
24
|
""""""
|
25
|
+
if name is None:
|
26
|
+
name = f"{type(self).__name__}:{id(self)}"
|
27
|
+
|
31
28
|
self.name = name
|
32
|
-
self.should_store_memory_usage = should_store_memory_usage
|
33
29
|
self.message_width = message_width
|
34
30
|
#
|
35
31
|
self.MessageFromRecord: MessageFromRecord_h | None = None
|
@@ -38,8 +34,6 @@ class _base_t:
|
|
38
34
|
|
39
35
|
def __post_init__(self) -> None:
|
40
36
|
""""""
|
41
|
-
global _MEMORY_MEASURE_ERROR
|
42
|
-
|
43
37
|
if self.name in HANDLER_KINDS:
|
44
38
|
raise ValueError(
|
45
39
|
MessageWithActualExpected(
|
@@ -52,12 +46,6 @@ class _base_t:
|
|
52
46
|
if self.name is None:
|
53
47
|
self.name = TimeStamp()
|
54
48
|
|
55
|
-
if self.should_store_memory_usage and not CanCheckMemoryUsage():
|
56
|
-
self.should_store_memory_usage = False
|
57
|
-
if _MEMORY_MEASURE_ERROR is not None:
|
58
|
-
s.__stderr__.write(_MEMORY_MEASURE_ERROR + "\n")
|
59
|
-
_MEMORY_MEASURE_ERROR = None
|
60
|
-
|
61
49
|
if 0 < self.message_width < FALLBACK_MESSAGE_WIDTH:
|
62
50
|
self.message_width = FALLBACK_MESSAGE_WIDTH
|
63
51
|
|
@@ -84,7 +72,6 @@ class handler_t(l.Handler, _base_t):
|
|
84
72
|
def __init__(
|
85
73
|
self,
|
86
74
|
name: str | None,
|
87
|
-
should_store_memory_usage: bool,
|
88
75
|
message_width: int,
|
89
76
|
level: int,
|
90
77
|
formatter: l.Formatter | None,
|
@@ -92,7 +79,7 @@ class handler_t(l.Handler, _base_t):
|
|
92
79
|
) -> None:
|
93
80
|
""""""
|
94
81
|
l.Handler.__init__(self)
|
95
|
-
_base_t.__init__(self, name,
|
82
|
+
_base_t.__init__(self, name, message_width)
|
96
83
|
__post_init__(self, level, formatter)
|
97
84
|
|
98
85
|
|
@@ -100,7 +87,6 @@ class file_handler_t(l.FileHandler, _base_t):
|
|
100
87
|
def __init__(
|
101
88
|
self,
|
102
89
|
name: str | None,
|
103
|
-
should_store_memory_usage: bool,
|
104
90
|
message_width: int,
|
105
91
|
level: int,
|
106
92
|
formatter: l.Formatter | None,
|
@@ -116,7 +102,7 @@ class file_handler_t(l.FileHandler, _base_t):
|
|
116
102
|
raise ValueError(f"File or folder already exists: {path}.")
|
117
103
|
|
118
104
|
l.FileHandler.__init__(self, path)
|
119
|
-
_base_t.__init__(self, name,
|
105
|
+
_base_t.__init__(self, name, message_width)
|
120
106
|
__post_init__(self, level, formatter)
|
121
107
|
|
122
108
|
|
logger_36/type/logger.py
CHANGED
@@ -5,9 +5,11 @@ SEE COPYRIGHT NOTICE BELOW
|
|
5
5
|
"""
|
6
6
|
|
7
7
|
import dataclasses as d
|
8
|
+
import inspect as e
|
8
9
|
import logging as l
|
9
10
|
import sys as s
|
10
11
|
import textwrap as text
|
12
|
+
import threading as thrd
|
11
13
|
import traceback as tcbk
|
12
14
|
import types as t
|
13
15
|
import typing as h
|
@@ -27,8 +29,9 @@ from logger_36.config.message import (
|
|
27
29
|
LONG_ENOUGH,
|
28
30
|
TIME_FORMAT,
|
29
31
|
)
|
32
|
+
from logger_36.constant.error import MEMORY_MEASURE_ERROR
|
30
33
|
from logger_36.constant.generic import NOT_PASSED
|
31
|
-
from logger_36.constant.handler import
|
34
|
+
from logger_36.constant.handler import HANDLER_KINDS, handler_codes_h
|
32
35
|
from logger_36.constant.issue import ISSUE_LEVEL_SEPARATOR, ORDER, order_h
|
33
36
|
from logger_36.constant.logger import (
|
34
37
|
LOGGER_NAME,
|
@@ -38,15 +41,11 @@ from logger_36.constant.logger import (
|
|
38
41
|
from logger_36.constant.memory import UNKNOWN_MEMORY_USAGE
|
39
42
|
from logger_36.constant.message import LINE_INDENT, TIME_LENGTH_m_1, expected_op_h
|
40
43
|
from logger_36.constant.path import PROJECT_FILE_RELATIVE
|
41
|
-
from logger_36.constant.record import
|
42
|
-
HIDE_WHERE_ATTR,
|
43
|
-
SHOW_W_RULE_ATTR,
|
44
|
-
STORE_MEMORY_ATTR,
|
45
|
-
)
|
46
|
-
from logger_36.extension.exception import OverrideExceptionFormat
|
44
|
+
from logger_36.constant.record import SHOW_W_RULE_ATTR, SHOW_WHERE_ATTR
|
47
45
|
from logger_36.task.format.message import MessageFromRecord, MessageWithActualExpected
|
48
46
|
from logger_36.task.format.rule import RuleAsText
|
49
47
|
from logger_36.task.measure.chronos import ElapsedTime
|
48
|
+
from logger_36.task.measure.memory import CanCheckUsage as CanCheckMemoryUsage
|
50
49
|
from logger_36.task.measure.memory import CurrentUsage as CurrentMemoryUsage
|
51
50
|
from logger_36.type.handler import any_handler_t as base_handler_t
|
52
51
|
from logger_36.type.issue import NewIssue, issue_t
|
@@ -66,6 +65,7 @@ logger_handle_h = logger_handle_raw_h | logger_handle_with_self_h
|
|
66
65
|
|
67
66
|
_DATE_TIME_ORIGIN = date_time_t.fromtimestamp(1970, None)
|
68
67
|
_DATE_ORIGIN = _DATE_TIME_ORIGIN.date()
|
68
|
+
_MEMORY_MEASURE_ERROR = MEMORY_MEASURE_ERROR
|
69
69
|
|
70
70
|
|
71
71
|
@d.dataclass(slots=True, repr=False, eq=False)
|
@@ -85,6 +85,7 @@ class logger_t(base_t):
|
|
85
85
|
"""
|
86
86
|
|
87
87
|
should_record_messages: bool = False
|
88
|
+
should_watch_memory_usage: bool = False
|
88
89
|
exit_on_error: bool = False # Implies exit_on_critical.
|
89
90
|
exit_on_critical: bool = False
|
90
91
|
|
@@ -93,7 +94,6 @@ class logger_t(base_t):
|
|
93
94
|
|
94
95
|
last_message_now: date_time_t = d.field(init=False, default=_DATE_TIME_ORIGIN)
|
95
96
|
last_message_date: date_t = d.field(init=False, default=_DATE_ORIGIN)
|
96
|
-
any_handler_stores_memory: bool = d.field(init=False, default=False)
|
97
97
|
memory_usages: list[tuple[str, int]] = d.field(init=False, default_factory=list)
|
98
98
|
context_levels: list[str] = d.field(init=False, default_factory=list)
|
99
99
|
staged_issues: list[issue_t] = d.field(init=False, default_factory=list)
|
@@ -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,8 +156,11 @@ 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
|
""""""
|
162
|
+
global _MEMORY_MEASURE_ERROR
|
163
|
+
|
159
164
|
base_t.__init__(self, name_)
|
160
165
|
self.setLevel(level_)
|
161
166
|
self.propagate = False # Part of base_t.
|
@@ -169,10 +174,18 @@ class logger_t(base_t):
|
|
169
174
|
self.ToggleWarningInterceptions(True)
|
170
175
|
if activate_log_interceptions:
|
171
176
|
self._should_activate_log_interceptions = True
|
177
|
+
if activate_exc_interceptions:
|
178
|
+
self.ToggleExceptionInterceptions(True)
|
172
179
|
|
173
180
|
if self.exit_on_error:
|
174
181
|
self.exit_on_critical = True
|
175
182
|
|
183
|
+
if self.should_watch_memory_usage and not CanCheckMemoryUsage():
|
184
|
+
self.should_watch_memory_usage = False
|
185
|
+
if _MEMORY_MEASURE_ERROR is not None:
|
186
|
+
s.__stderr__.write(_MEMORY_MEASURE_ERROR + "\n")
|
187
|
+
_MEMORY_MEASURE_ERROR = None
|
188
|
+
|
176
189
|
def handle(self, record: l.LogRecord, /) -> None:
|
177
190
|
""""""
|
178
191
|
elapsed_time, now = ElapsedTime(should_return_now=True)
|
@@ -219,12 +232,8 @@ class logger_t(base_t):
|
|
219
232
|
self.last_message_now = now
|
220
233
|
|
221
234
|
# Where.
|
222
|
-
|
223
|
-
|
224
|
-
should_show_where = (record.levelno != l.INFO) and not hasattr(
|
225
|
-
record, HIDE_WHERE_ATTR
|
226
|
-
)
|
227
|
-
if should_store_where or should_show_where:
|
235
|
+
should_show_where = getattr(record, SHOW_WHERE_ATTR, record.levelno != l.INFO)
|
236
|
+
if should_show_where or self.should_watch_memory_usage:
|
228
237
|
module = path_t(record.pathname)
|
229
238
|
for path in s.path:
|
230
239
|
if module.is_relative_to(path):
|
@@ -264,7 +273,7 @@ class logger_t(base_t):
|
|
264
273
|
|
265
274
|
self.events[record.levelno] += 1
|
266
275
|
|
267
|
-
if
|
276
|
+
if self.should_watch_memory_usage:
|
268
277
|
self.memory_usages.append((where, CurrentMemoryUsage()))
|
269
278
|
|
270
279
|
def SetLevel(self, level: int, /, *, which: handler_codes_h | str = "a") -> None:
|
@@ -296,7 +305,6 @@ class logger_t(base_t):
|
|
296
305
|
|
297
306
|
def MakeMonochrome(self) -> None:
|
298
307
|
""""""
|
299
|
-
OverrideExceptionFormat()
|
300
308
|
self.AddHandler(console_handler_t)
|
301
309
|
|
302
310
|
def MakeRich(self, *, alternating_logs: int = 0) -> None:
|
@@ -304,7 +312,6 @@ class logger_t(base_t):
|
|
304
312
|
if MISSING_RICH_MESSAGE is not None:
|
305
313
|
s.__stderr__.write(MISSING_RICH_MESSAGE + "\n")
|
306
314
|
|
307
|
-
OverrideExceptionFormat()
|
308
315
|
if console_rich_handler_t is console_handler_t:
|
309
316
|
handler_kwargs = {}
|
310
317
|
else:
|
@@ -313,7 +320,6 @@ class logger_t(base_t):
|
|
313
320
|
|
314
321
|
def MakePermanent(self, path: str | path_t, /) -> None:
|
315
322
|
""""""
|
316
|
-
OverrideExceptionFormat()
|
317
323
|
self.AddHandler(file_handler_t, path=path)
|
318
324
|
|
319
325
|
def ResetEventCounts(self) -> None:
|
@@ -377,6 +383,37 @@ class logger_t(base_t):
|
|
377
383
|
self.intercepted_log_handles.clear()
|
378
384
|
self.info("Log Interception: OFF")
|
379
385
|
|
386
|
+
def ToggleExceptionInterceptions(self, state: bool, /) -> None:
|
387
|
+
""""""
|
388
|
+
if state:
|
389
|
+
if self.intercepts_exceptions:
|
390
|
+
return
|
391
|
+
|
392
|
+
s.excepthook = self.DealWithException
|
393
|
+
thrd.excepthook = self.DealWithExceptionInThread
|
394
|
+
self.intercepts_exceptions = True
|
395
|
+
self.info("Exception Interception: ON")
|
396
|
+
else:
|
397
|
+
if not self.intercepts_exceptions:
|
398
|
+
return
|
399
|
+
|
400
|
+
s.excepthook = s.__excepthook__
|
401
|
+
thrd.excepthook = thrd.__excepthook__
|
402
|
+
self.intercepts_exceptions = False
|
403
|
+
self.info("Exception Interception: OFF")
|
404
|
+
|
405
|
+
def DealWithException(self, _, exc_value, exc_traceback, /) -> None:
|
406
|
+
""""""
|
407
|
+
exception = exc_value.with_traceback(exc_traceback)
|
408
|
+
self.LogException(exception, level=l.CRITICAL)
|
409
|
+
s.exit(1)
|
410
|
+
|
411
|
+
def DealWithExceptionInThread(
|
412
|
+
self, exc_type, exc_value, exc_traceback, _, /
|
413
|
+
) -> None:
|
414
|
+
""""""
|
415
|
+
self.DealWithException(exc_type, exc_value, exc_traceback)
|
416
|
+
|
380
417
|
def AddHandler(
|
381
418
|
self,
|
382
419
|
handler_t: type[base_handler_t],
|
@@ -384,7 +421,6 @@ class logger_t(base_t):
|
|
384
421
|
*,
|
385
422
|
name: str | None = None,
|
386
423
|
level: int = l.INFO,
|
387
|
-
should_store_memory_usage: bool = False,
|
388
424
|
message_width: int = -1,
|
389
425
|
formatter: l.Formatter | None = None,
|
390
426
|
should_still_hold_messages: bool = False,
|
@@ -396,9 +432,9 @@ class logger_t(base_t):
|
|
396
432
|
self._should_activate_log_interceptions = False
|
397
433
|
|
398
434
|
self._should_hold_messages = should_still_hold_messages
|
435
|
+
|
399
436
|
handler = handler_t.New(
|
400
437
|
name=name,
|
401
|
-
should_store_memory_usage=should_store_memory_usage,
|
402
438
|
message_width=message_width,
|
403
439
|
level=level,
|
404
440
|
formatter=formatter,
|
@@ -406,31 +442,26 @@ class logger_t(base_t):
|
|
406
442
|
)
|
407
443
|
base_t.addHandler(self, handler)
|
408
444
|
|
409
|
-
extension = getattr(handler, "extension", None)
|
410
|
-
if extension is None:
|
411
|
-
name = handler.name
|
412
|
-
if (name is None) or (name.__len__() == 0):
|
413
|
-
name = ANONYMOUS
|
414
|
-
else:
|
415
|
-
name = getattr(extension, "name", ANONYMOUS)
|
416
|
-
if getattr(extension, STORE_MEMORY_ATTR, False):
|
417
|
-
self.any_handler_stores_memory = True
|
418
|
-
|
419
445
|
path = getattr(handler, "baseFilename", "")
|
420
446
|
if isinstance(path, path_t) or (path.__len__() > 0):
|
421
447
|
path = f"\nPath: {path}"
|
422
|
-
|
423
448
|
self.info(
|
424
|
-
f'New handler "{name}" of type "{type(handler).__name__}" and '
|
449
|
+
f'New handler "{handler.name}" of type "{type(handler).__name__}" and '
|
425
450
|
f"level {handler.level}={l.getLevelName(handler.level)}{path}"
|
426
451
|
)
|
427
452
|
|
428
453
|
def __call__(self, *args, **kwargs) -> None:
|
429
454
|
"""
|
430
|
-
For a print-like calling.
|
455
|
+
For a print-like calling for print-based debugging.
|
431
456
|
"""
|
457
|
+
frame = e.stack(context=0)[1][0] # 1=caller.
|
458
|
+
details = e.getframeinfo(frame, context=0)
|
459
|
+
path = path_t(details.filename).relative_to(path_t.home())
|
460
|
+
where = f"{str(path)[:-3]}.{details.function}.{details.lineno}"
|
461
|
+
|
432
462
|
separator = kwargs.get("separator", " ")
|
433
|
-
|
463
|
+
|
464
|
+
self.info(where + "\n" + separator.join(map(str, args)))
|
434
465
|
|
435
466
|
def Log(
|
436
467
|
self,
|
@@ -476,8 +507,8 @@ class logger_t(base_t):
|
|
476
507
|
# - Why it's not: "\n".join(lines)?
|
477
508
|
# - Why adding exception name here and not when removing caller?
|
478
509
|
formatted = "".join(lines)
|
479
|
-
message = f"{type(exception).__name__}
|
480
|
-
self.log(level, message)
|
510
|
+
message = f"Exception of type {type(exception).__name__}\n----\n{formatted}"
|
511
|
+
self.log(level, message, extra={SHOW_WHERE_ATTR: False})
|
481
512
|
|
482
513
|
def LogAsIs(self, message: str, /, *, indented: bool = False) -> None:
|
483
514
|
""""""
|
@@ -591,7 +622,7 @@ class logger_t(base_t):
|
|
591
622
|
formatted = "\n".join(lines)
|
592
623
|
"""
|
593
624
|
|
594
|
-
hide_where = {
|
625
|
+
hide_where = {SHOW_WHERE_ATTR: False}
|
595
626
|
if unified:
|
596
627
|
level, _ = issues[0].split(ISSUE_LEVEL_SEPARATOR, maxsplit=1)
|
597
628
|
wo_level = []
|
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=SlgS0Uo9sKB6vpjWQKryKeGsW_DST0lxy888VpF5J5Q,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,13 +9,13 @@ 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=
|
14
|
-
logger_36/catalog/handler/console_rich.py,sha256=
|
15
|
-
logger_36/catalog/handler/file.py,sha256=
|
16
|
-
logger_36/catalog/handler/generic.py,sha256=
|
12
|
+
logger_36/catalog/handler/console.py,sha256=nczZAIlkolkuTG5TMipqJJTtlwg58HQE1q-9hVyelCg,2951
|
13
|
+
logger_36/catalog/handler/console_rich.py,sha256=cZHFM9fHxdEnzhVg1S94wa0P_QOSTO4O1oQxigpNA0s,6907
|
14
|
+
logger_36/catalog/handler/file.py,sha256=jZEoKPUjK5MlvzxgxXICH7jJLnHr7vDw42tv7GqopiA,3181
|
15
|
+
logger_36/catalog/handler/generic.py,sha256=nfJSi0mghbSfSfZa4VV5jTetDV8ykEIkkRxRkIC084Y,7989
|
17
16
|
logger_36/catalog/logger/chronos.py,sha256=ocY13f98EfknU7wZCv0FS9Xb7pTNaWCPSusXFIEvEd4,2437
|
18
17
|
logger_36/catalog/logger/gpu.py,sha256=ybn7Q8exiqoigvNpzEhg0Zp027WogypuNJwfsQ1pRY4,3416
|
19
|
-
logger_36/catalog/logger/memory.py,sha256=
|
18
|
+
logger_36/catalog/logger/memory.py,sha256=aSLHDQPacPE2FJlpBRItVhQA0KxzkFDFPXPn3TcZ8Dg,4779
|
20
19
|
logger_36/catalog/logger/system.py,sha256=3VWbceSAknZwmRhEfd8pkuLwU2B8zPhCGNGQE0h5KLo,3065
|
21
20
|
logger_36/config/issue.py,sha256=G-i5p6lhZCLAOa-VTMyL9ZonvGCvhdoQ5KZdSWgP-FU,2267
|
22
21
|
logger_36/config/memory.py,sha256=yCX5phsB_KJMr5xHpVUeOHFhAA7p_8yahP3X28VndOY,2217
|
@@ -24,16 +23,15 @@ logger_36/config/message.py,sha256=mgPcMS7qWBuqP2w5NoHw1df32kcVToVhisozb32_EII,2
|
|
24
23
|
logger_36/config/system.py,sha256=HD8ZuwsXhEAExeZrww8YoDkQGMs4T5RDqQMb1W4qVgc,2477
|
25
24
|
logger_36/constant/error.py,sha256=LzsS_P1IoH3ct_ifNWi9LzJ-X_Y5DN1naTLwwIFzDQA,2827
|
26
25
|
logger_36/constant/generic.py,sha256=t6aRb66_NHwMhR1p7BZ4QXTU2jpLz-H5YAL4PuMtKx8,2244
|
27
|
-
logger_36/constant/handler.py,sha256=
|
26
|
+
logger_36/constant/handler.py,sha256=tnTr6JvObgL6LPIX77HR5uXQvwqAT8hbKvEWfKkzlCo,2351
|
28
27
|
logger_36/constant/html.py,sha256=-m1CDyDN0kkurloEtJeqBsyxy9nXCImIMGLwEIF33M0,2515
|
29
28
|
logger_36/constant/issue.py,sha256=01l8itRPWGS5F6gXtsXUJgGR-4lS1Eu3_YeKC-khKLw,2315
|
30
29
|
logger_36/constant/logger.py,sha256=2qRkteblpbHrq9x0aiw9MPquyXrSRd6_yMQnPEhFp2U,2468
|
31
30
|
logger_36/constant/memory.py,sha256=ZL1MwbdtNsrCrOwzEyfTsfOoOsRBTJtbbf3otHGnxXo,2343
|
32
31
|
logger_36/constant/message.py,sha256=Ys_CAyhENlT8Z3rr-AxO4hjdl1jLsKzVSPQ8wqLOCPQ,2838
|
33
|
-
logger_36/constant/path.py,sha256=
|
34
|
-
logger_36/constant/record.py,sha256=
|
32
|
+
logger_36/constant/path.py,sha256=hNT_Ut8NMWVW826eUZsJ5ieFeihFKXZBcLOUszJYn8g,2753
|
33
|
+
logger_36/constant/record.py,sha256=D_VDC5m5_LGcoV6YBb5hE6CLioUPFGX8hzcMdMazRoM,2260
|
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=RlYVGxP6jfLqKJH-KvJBunPrjmcQ-gcoQzr6Hw4dOdk,5962
|
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=6q_9nbbumyF0aXupl36Xc_06gJ2aE7k39ZQwSffXQnI,26319
|
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.17.dist-info/METADATA,sha256=lniQQRbIv0AHbWw_iEoVZjm3ZKBTKQW-1BXXXdKv6fs,6506
|
52
|
+
logger_36-2025.17.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
53
|
+
logger_36-2025.17.dist-info/top_level.txt,sha256=sM95BTMWmslEEgR_1pzwZsOeSp8C_QBiu8ImbFr0XLc,10
|
54
|
+
logger_36-2025.17.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
|