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.
@@ -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, should_store_memory_usage, message_width, level, formatter)
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.any_handler_stores_memory:
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.any_handler_stores_memory:
80
- where, max_usage = logger.max_memory_usage_full
81
- value, unit = FormattedUsage(max_usage, unit=unit, decimals=decimals)
82
- logger.info(f"Max. Memory Usage: {value}{unit} near {where}")
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
  """
@@ -9,8 +9,6 @@ import typing as h
9
9
  handler_codes_h = h.Literal["g", "c", "f", "a"] # g=generic, c=console, f=file, a=all.
10
10
  HANDLER_KINDS: tuple[str, ...] = h.get_args(handler_codes_h)
11
11
 
12
- ANONYMOUS = "<Anonymous>"
13
-
14
12
  """
15
13
  COPYRIGHT NOTICE
16
14
 
@@ -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 nspt
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 = nspt.stack()[-1]
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):
@@ -5,8 +5,7 @@ SEE COPYRIGHT NOTICE BELOW
5
5
  """
6
6
 
7
7
  SHOW_W_RULE_ATTR = "should_show_w_rule"
8
- STORE_MEMORY_ATTR = "should_store_memory_usage"
9
- HIDE_WHERE_ATTR = "should_hide_where"
8
+ SHOW_WHERE_ATTR = "should_show_where"
10
9
 
11
10
  """
12
11
  COPYRIGHT NOTICE
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, should_store_memory_usage, message_width)
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, should_store_memory_usage, message_width)
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 ANONYMOUS, HANDLER_KINDS, handler_codes_h
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
- # Memory usage is also stored if there are no handlers yet, just in case.
223
- should_store_where = self.any_handler_stores_memory or not self.hasHandlers()
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 should_store_where:
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
- self.info(separator.join(map(str, args)))
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__}:\n{formatted}"
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 = {HIDE_WHERE_ATTR: None}
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(self, uid: h.Hashable, /) -> None:
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
- self.Add(uid, logger_t())
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
@@ -4,7 +4,7 @@ Contributor(s): Eric Debreuve (eric.debreuve@cnrs.fr) since 2023
4
4
  SEE COPYRIGHT NOTICE BELOW
5
5
  """
6
6
 
7
- __version__ = "2025.15"
7
+ __version__ = "2025.17"
8
8
 
9
9
  """
10
10
  COPYRIGHT NOTICE
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: logger-36
3
- Version: 2025.15
3
+ Version: 2025.17
4
4
  Summary: Simple logger with a catalog of handlers
5
5
  Home-page: https://src.koda.cnrs.fr/eric.debreuve/logger-36/
6
6
  Author: Eric Debreuve
@@ -1,7 +1,6 @@
1
1
  logger_36/__init__.py,sha256=UhKxuQLS1Pfgt5H0K_7BaDAPejOUR8byD5BYRCnHQMQ,2655
2
- logger_36/version.py,sha256=oFhR-WWJSP1I096JdyMWykVW-yQE68ygNDxM43rM030,2206
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=Dc9Iyg7yLqUh3H_KD1B0oou5eh7tqGxZi9x45GOLTJA,3027
14
- logger_36/catalog/handler/console_rich.py,sha256=U4hD8qF88dpDALKkeOvwnrJpUbUpG5egq1JfImU4pFg,7168
15
- logger_36/catalog/handler/file.py,sha256=h6goKVAPfrYRIM8ypdyTsZKlSaj_7O-GghQquf0-zL4,3279
16
- logger_36/catalog/handler/generic.py,sha256=rubsfh6Bbs2CFbUF2Wb3VG4AGgRAgP1nZYEV7-ukVY0,8250
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=CWhr2J4BqArJxzH6tS-ZThr-rYPAQGtuLn0pP7Iryfg,4685
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=PQUehMK9Yg0_rBDcMc8xpUbAsCauCLy_eS_ntiWew1Y,2378
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=fKJn2vGj012BU5DFRetDFus_tKMty2q_WL0J2KrXdCo,2731
34
- logger_36/constant/record.py,sha256=9Q28lVH_s0og4v74delgwIPAJ9G28I5rBM-brXcoY80,2308
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=2Q3crkhIzMLyuT7pBtpmouXgKWbULdsYw8vxQZBCT2g,6637
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=X2qax6gPcT6lPsfNKM2aL5yHb_RUtIGJPWJ_GBxKSTU,25021
51
- logger_36/type/loggers.py,sha256=znqxWBnfQxvkg3VUfbTUvt3S6Kq0DAzWWepxQDt9suI,2871
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.15.dist-info/METADATA,sha256=wKz-PcmHE1ZvHLy4gj6pLm-2CcY_F2t8wE14ZbYGxsw,6506
54
- logger_36-2025.15.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
55
- logger_36-2025.15.dist-info/top_level.txt,sha256=sM95BTMWmslEEgR_1pzwZsOeSp8C_QBiu8ImbFr0XLc,10
56
- logger_36-2025.15.dist-info/RECORD,,
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,,
@@ -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
- """
@@ -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
- """