logger-36 2025.24__py3-none-any.whl → 2025.25__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/type/handler.py CHANGED
@@ -8,15 +8,14 @@ import logging as l
8
8
  import typing as h
9
9
  from pathlib import Path as path_t
10
10
 
11
- from logger_36.config.message import (
12
- FALLBACK_MESSAGE_WIDTH,
13
- LEVEL_CLOSING,
14
- LEVEL_OPENING,
15
- MESSAGE_MARKER,
16
- WHERE_SEPARATOR,
17
- )
11
+ from logger_36.config.message import FALLBACK_MESSAGE_WIDTH
18
12
  from logger_36.config.rule import DEFAULT_RULE_LENGTH, RULE_CHARACTER
19
- from logger_36.constant.message import NEXT_LINE_PROLOGUE
13
+ from logger_36.constant.message import (
14
+ NEXT_LINE_PROLOGUE,
15
+ TIME_PLACEHOLDER,
16
+ WHERE_PROLOGUE,
17
+ CONTEXT_LENGTH_p_1,
18
+ )
20
19
  from logger_36.constant.record import SHOW_W_RULE_ATTR, WHEN_OR_ELAPSED_ATTR, WHERE_ATTR
21
20
  from logger_36.constant.rule import DEFAULT_RULE, MIN_HALF_RULE_LENGTH
22
21
  from logger_36.extension.line import WrappedLines
@@ -53,41 +52,40 @@ class extension_t:
53
52
 
54
53
  def MessageFromRecord(
55
54
  self, record: l.LogRecord, /, *, rule_color: str = "black"
56
- ) -> tuple[str, bool]:
55
+ ) -> tuple[str, bool, int | None]:
57
56
  """
58
- The second returned value is is_not_a_rule.
57
+ Arguments from second on: is_not_a_rule, where_location.
59
58
  """
60
59
  message = record.msg # See logger_36.catalog.handler.README.txt.
61
60
  if self.PreProcessedMessage is not None:
62
61
  message = self.PreProcessedMessage(message)
63
62
 
64
63
  if hasattr(record, SHOW_W_RULE_ATTR):
65
- return self.Rule(text=message, color=rule_color), False
64
+ return self.Rule(text=message, color=rule_color), False, None
66
65
 
67
66
  if (self.message_width <= 0) or (message.__len__() <= self.message_width):
68
67
  if "\n" in message:
69
68
  message = NEXT_LINE_PROLOGUE.join(message.splitlines())
70
69
  else:
71
70
  if "\n" in message:
72
- lines = WrappedLines(message.splitlines(), self.message_width)
71
+ lines = message.splitlines()
73
72
  else:
74
- lines = WrappedLines([message], self.message_width)
75
- message = NEXT_LINE_PROLOGUE.join(lines)
76
-
77
- when_or_elapsed = getattr(record, WHEN_OR_ELAPSED_ATTR, None)
78
- if when_or_elapsed is None:
79
- return message, True
73
+ lines = [message]
74
+ message = NEXT_LINE_PROLOGUE.join(WrappedLines(lines, self.message_width))
80
75
 
76
+ when_or_elapsed = getattr(record, WHEN_OR_ELAPSED_ATTR, TIME_PLACEHOLDER)
81
77
  if (where := getattr(record, WHERE_ATTR, None)) is None:
78
+ where_location = None
82
79
  where = ""
83
80
  else:
84
- where = f"{NEXT_LINE_PROLOGUE}{WHERE_SEPARATOR} {where}"
81
+ where_location = CONTEXT_LENGTH_p_1 + message.__len__()
82
+ where = f"{WHERE_PROLOGUE}{where}"
85
83
 
86
84
  return (
87
- f"{when_or_elapsed}"
88
- f"{LEVEL_OPENING}{record.levelname[0]}{LEVEL_CLOSING} "
89
- f"{MESSAGE_MARKER} {message}{where}"
90
- ), True
85
+ f"{when_or_elapsed}_{record.levelname[0].lower()} {message}{where}",
86
+ True,
87
+ where_location,
88
+ )
91
89
 
92
90
  def Rule(self, /, *, text: str | None = None, color: str = "black") -> str | h.Any:
93
91
  """
logger_36/type/issue.py CHANGED
@@ -8,9 +8,9 @@ import logging as l
8
8
  import typing as h
9
9
 
10
10
  from logger_36.config.issue import ISSUE_BASE_CONTEXT
11
- from logger_36.constant.generic import NOT_PASSED
12
11
  from logger_36.constant.issue import ISSUE_LEVEL_SEPARATOR
13
12
  from logger_36.constant.message import expected_op_h
13
+ from logger_36.extension.sentinel import NOT_PASSED
14
14
  from logger_36.task.format.message import MessageWithActualExpected
15
15
 
16
16
  issue_t = str
@@ -28,11 +28,11 @@ def NewIssue(
28
28
  expected_is_choices: bool = False,
29
29
  expected_op: expected_op_h = "=",
30
30
  with_final_dot: bool = True,
31
- ) -> issue_t:
31
+ ) -> tuple[issue_t, bool]:
32
32
  """"""
33
33
  if context.__len__() == 0:
34
34
  context = ISSUE_BASE_CONTEXT
35
- message = MessageWithActualExpected(
35
+ message, has_actual_expected = MessageWithActualExpected(
36
36
  message,
37
37
  actual=actual,
38
38
  expected=expected,
@@ -41,7 +41,10 @@ def NewIssue(
41
41
  with_final_dot=with_final_dot,
42
42
  )
43
43
 
44
- return f"{level}{ISSUE_LEVEL_SEPARATOR}{context}{separator}{message}"
44
+ return (
45
+ f"{level}{ISSUE_LEVEL_SEPARATOR}{context}{separator}{message}",
46
+ has_actual_expected,
47
+ )
45
48
 
46
49
 
47
50
  """
logger_36/type/logger.py CHANGED
@@ -7,6 +7,7 @@ SEE COPYRIGHT NOTICE BELOW
7
7
  import dataclasses as d
8
8
  import inspect as e
9
9
  import logging as l
10
+ import multiprocessing as prll
10
11
  import sys as s
11
12
  import textwrap as text
12
13
  import threading as thrd
@@ -15,6 +16,8 @@ import types as t
15
16
  import typing as h
16
17
  from datetime import date as date_t
17
18
  from datetime import datetime as date_time_t
19
+ from logging.handlers import QueueHandler as queue_handler_t
20
+ from logging.handlers import QueueListener as log_server_t
18
21
  from pathlib import Path as path_t
19
22
  from traceback import TracebackException as traceback_t
20
23
 
@@ -26,25 +29,32 @@ from logger_36.catalog.config.optional import (
26
29
  )
27
30
  from logger_36.catalog.handler.console import console_handler_t
28
31
  from logger_36.catalog.handler.file import file_handler_t
32
+ from logger_36.catalog.handler.memory import memory_handler_t, records_h
29
33
  from logger_36.config.issue import ISSUE_CONTEXT_END, ISSUE_CONTEXT_SEPARATOR
30
34
  from logger_36.config.message import (
31
35
  DATE_FORMAT,
32
- ELAPSED_TIME_SEPARATOR,
33
36
  LONG_ENOUGH,
34
37
  TIME_FORMAT,
35
38
  WHERE_SEPARATOR,
36
39
  )
37
- from logger_36.constant.date_time import DATE_ORIGIN, DATE_TIME_ORIGIN
38
- from logger_36.constant.generic import NOT_PASSED
40
+ from logger_36.constant.chronos import DATE_ORIGIN, DATE_TIME_ORIGIN
39
41
  from logger_36.constant.issue import ISSUE_LEVEL_SEPARATOR, ORDER, order_h
40
42
  from logger_36.constant.logger import WARNING_LOGGER_NAME, WARNING_TYPE_COMPILED_PATTERN
41
43
  from logger_36.constant.memory import UNKNOWN_MEMORY_USAGE
42
- from logger_36.constant.message import LINE_INDENT, TIME_LENGTH_m_1, expected_op_h
44
+ from logger_36.constant.message import LINE_INDENT, expected_op_h
43
45
  from logger_36.constant.path import USER_FOLDER, LAUNCH_ROOT_FILE_relative
44
- from logger_36.constant.record import SHOW_W_RULE_ATTR, SHOW_WHERE_ATTR
45
- from logger_36.extension.record import RecordLocation
46
+ from logger_36.constant.record import (
47
+ HAS_ACTUAL_EXPECTED_ATTR,
48
+ SHOW_W_RULE_ATTR,
49
+ SHOW_WHEN_ATTR,
50
+ SHOW_WHERE_ATTR,
51
+ WHEN_OR_ELAPSED_ATTR,
52
+ WHERE_ATTR,
53
+ )
54
+ from logger_36.extension.file import NewTemporaryFile
55
+ from logger_36.extension.sentinel import NOT_PASSED
46
56
  from logger_36.task.format.message import MessageWithActualExpected
47
- from logger_36.task.measure.chronos import ElapsedTime
57
+ from logger_36.task.measure.chronos import FormattedElapsedTime
48
58
  from logger_36.task.measure.memory import CurrentUsage as CurrentMemoryUsage
49
59
  from logger_36.type.handler import extension_t as handler_extension_t
50
60
  from logger_36.type.handler import handler_h as base_handler_h
@@ -63,6 +73,8 @@ logger_handle_raw_h = h.Callable[[l.LogRecord], None]
63
73
  logger_handle_with_self_h = h.Callable[[l.Logger, l.LogRecord], None]
64
74
  logger_handle_h = logger_handle_raw_h | logger_handle_with_self_h
65
75
 
76
+ MAIN_PROCESS_NAME = "MainProcess"
77
+
66
78
 
67
79
  @d.dataclass(slots=True, repr=False, eq=False)
68
80
  class logger_t(base_t):
@@ -87,7 +99,9 @@ class logger_t(base_t):
87
99
  last_message_date: date_t = d.field(init=False, default=DATE_ORIGIN)
88
100
  memory_usages: list[tuple[str, int]] = d.field(init=False, default_factory=list)
89
101
  context_levels: list[str] = d.field(init=False, default_factory=list)
90
- staged_issues: list[issue_t] = d.field(init=False, default_factory=list)
102
+ staged_issues: list[tuple[issue_t, bool]] = d.field(
103
+ init=False, default_factory=list
104
+ )
91
105
  intercepted_wrn_handle: logger_handle_h | None = d.field(init=False, default=None)
92
106
  intercepted_log_handles: dict[str, logger_handle_h] = d.field(
93
107
  init=False, default_factory=dict
@@ -97,6 +111,8 @@ class logger_t(base_t):
97
111
  # Used only until the first handler is added (see AddHandler).
98
112
  _should_activate_log_interceptions: bool = d.field(init=False, default=False)
99
113
 
114
+ log_server: log_server_t | None = d.field(init=False, default=None)
115
+
100
116
  name_: d.InitVar[str | None] = None
101
117
  level_: d.InitVar[int] = l.NOTSET
102
118
  activate_wrn_interceptions: d.InitVar[bool] = True
@@ -109,6 +125,21 @@ class logger_t(base_t):
109
125
  FormattedEntry = lambda _: f"{_[0]}: {_[1].replace('\n', '↲ ')}"
110
126
  return "\n".join(map(FormattedEntry, self.history.items()))
111
127
 
128
+ @property
129
+ def records(self) -> records_h | None:
130
+ """"""
131
+ return logger_t.Records(self)
132
+
133
+ @staticmethod
134
+ def Records(logger: base_t | l.Logger, /) -> records_h | None:
135
+ """"""
136
+ for handler in logger.handlers:
137
+ output = getattr(handler, "records", None)
138
+ if memory_handler_t.AreRecords(output):
139
+ return output
140
+
141
+ return None
142
+
112
143
  @property
113
144
  def intercepts_warnings(self) -> bool:
114
145
  """"""
@@ -156,6 +187,8 @@ class logger_t(base_t):
156
187
  activate_exc_interceptions: bool,
157
188
  ) -> None:
158
189
  """"""
190
+ assert prll.current_process().name == MAIN_PROCESS_NAME
191
+
159
192
  if name_ is None:
160
193
  name_ = f"{type(self).__name__}:{hex(id(self))[2:]}"
161
194
 
@@ -185,38 +218,39 @@ class logger_t(base_t):
185
218
 
186
219
  def handle(self, record: l.LogRecord, /) -> None:
187
220
  """"""
188
- elapsed_time, now = ElapsedTime(should_return_now=True)
189
-
221
+ now = date_time_t.now()
190
222
  if (date := now.date()) != self.last_message_date:
191
223
  self._AcknowledgeDateChange(date)
192
224
 
225
+ level = record.levelno
226
+
193
227
  # When.
194
- if now - self.last_message_now > LONG_ENOUGH:
195
- w_or_e = now.strftime(TIME_FORMAT)
196
- else:
197
- w_or_e = f"{ELAPSED_TIME_SEPARATOR}{elapsed_time:.<{TIME_LENGTH_m_1}}"
198
- record.when_or_elapsed = w_or_e
228
+ if getattr(record, SHOW_WHEN_ATTR, True):
229
+ if now - self.last_message_now > LONG_ENOUGH:
230
+ w_or_e = f"{now:{TIME_FORMAT}}"
231
+ else:
232
+ w_or_e = FormattedElapsedTime(now) # or: f"{[...]:.<{TIME_LENGTH}}".
233
+ setattr(record, WHEN_OR_ELAPSED_ATTR, w_or_e)
199
234
  self.last_message_now = now
200
235
 
201
236
  # Where.
202
- should_show_where = getattr(record, SHOW_WHERE_ATTR, record.levelno != l.INFO)
237
+ should_show_where = getattr(record, SHOW_WHERE_ATTR, level != l.INFO)
203
238
  if should_show_where or self.should_monitor_memory_usage:
204
- where = RecordLocation(record, should_show_where)
205
- else:
206
- where = None
239
+ where = f"{record.pathname}:{record.funcName}:{record.lineno}"
240
+ if should_show_where:
241
+ setattr(record, WHERE_ATTR, where)
242
+ if self.should_monitor_memory_usage:
243
+ self.memory_usages.append((where, CurrentMemoryUsage()))
207
244
 
208
245
  # What.
209
246
  if not isinstance(record.msg, str):
210
247
  record.msg = str(record.msg)
211
248
 
212
249
  base_t.handle(self, record)
213
- self.n_events[record.levelno] += 1
250
+ self.n_events[level] += 1
214
251
 
215
- if self.should_monitor_memory_usage:
216
- self.memory_usages.append((where, CurrentMemoryUsage()))
217
-
218
- if (self.exit_on_critical and (record.levelno is l.CRITICAL)) or (
219
- self.exit_on_error and (record.levelno is l.ERROR)
252
+ if (self.exit_on_critical and (level is l.CRITICAL)) or (
253
+ self.exit_on_error and (level is l.ERROR)
220
254
  ):
221
255
  # Also works if self.exit_on_error and record.levelno is l.CRITICAL since
222
256
  # __post_init__ set self.exit_on_critical if self.exit_on_error.
@@ -230,7 +264,7 @@ class logger_t(base_t):
230
264
  {
231
265
  "name": self.name,
232
266
  "levelno": l.INFO, # For management by logging.Logger.handle.
233
- "msg": f"DATE: {date.strftime(DATE_FORMAT)}",
267
+ "msg": f"DATE: {date:{DATE_FORMAT}}",
234
268
  SHOW_W_RULE_ATTR: True,
235
269
  }
236
270
  )
@@ -390,6 +424,27 @@ class logger_t(base_t):
390
424
  """"""
391
425
  self.AddHandler(file_handler_t, path=path)
392
426
 
427
+ def MakeMultiSafe(self) -> None:
428
+ """
429
+ Should not be called until after all desired handlers have been added (as a
430
+ better-then-nothing check, it is checked that the logger has at least one
431
+ handler). If handlers are added passed this call, execution might freeze or
432
+ crash.
433
+ """
434
+ assert self.log_server is None
435
+ assert self.hasHandlers()
436
+
437
+ handlers = tuple(self.handlers) # Making a copy is necessary.
438
+ for handler in handlers:
439
+ self.removeHandler(handler)
440
+
441
+ queue = prll.Queue()
442
+
443
+ self.addHandler(queue_handler_t(queue))
444
+
445
+ self.log_server = log_server_t(queue, *handlers)
446
+ self.log_server.start()
447
+
393
448
  def __call__(self, *args, **kwargs) -> None:
394
449
  """
395
450
  For a print-like calling for print-based debugging.
@@ -401,7 +456,7 @@ class logger_t(base_t):
401
456
  path = path_t(details.filename)
402
457
  if path.is_relative_to(USER_FOLDER):
403
458
  path = path.relative_to(USER_FOLDER)
404
- where = f"{str(path.with_suffix(''))}.{details.function}.{details.lineno}"
459
+ where = f"{str(path.with_suffix(''))}:{details.function}:{details.lineno}"
405
460
 
406
461
  self.info(separator.join(map(str, args)) + f"\n{WHERE_SEPARATOR} " + where)
407
462
 
@@ -420,7 +475,7 @@ class logger_t(base_t):
420
475
  """"""
421
476
  if isinstance(level, str):
422
477
  level = l.getLevelNamesMapping()[level.upper()]
423
- message = MessageWithActualExpected(
478
+ message, has_actual_expected = MessageWithActualExpected(
424
479
  message,
425
480
  actual=actual,
426
481
  expected=expected,
@@ -428,7 +483,11 @@ class logger_t(base_t):
428
483
  expected_op=expected_op,
429
484
  with_final_dot=with_final_dot,
430
485
  )
431
- self.log(level, message)
486
+ if has_actual_expected:
487
+ extra = {HAS_ACTUAL_EXPECTED_ATTR: True}
488
+ else:
489
+ extra = {}
490
+ self.log(level, message, extra=extra)
432
491
 
433
492
  def LogAsIs(self, message: str, /, *, indented: bool = False) -> None:
434
493
  """"""
@@ -472,11 +531,9 @@ class logger_t(base_t):
472
531
  self.LogException(exception, level=l.CRITICAL)
473
532
  s.exit(1)
474
533
 
475
- def DealWithExceptionInThread(
476
- self, exc_type, exc_value, exc_traceback, _, /
477
- ) -> None:
534
+ def DealWithExceptionInThread(self, args, /) -> None:
478
535
  """"""
479
- self.DealWithException(exc_type, exc_value, exc_traceback)
536
+ self.DealWithException(args.exc_type, args.exc_value, args.exc_traceback)
480
537
 
481
538
  def DisplayRule(
482
539
  self, /, *, message: str | None = None, color: str = "white"
@@ -527,7 +584,9 @@ class logger_t(base_t):
527
584
  )
528
585
  self.staged_issues.append(issue)
529
586
 
530
- def PopIssues(self, /, *, should_remove_context: bool = False) -> list[str]:
587
+ def PopIssues(
588
+ self, /, *, should_remove_context: bool = False
589
+ ) -> list[tuple[str, bool]]:
531
590
  """"""
532
591
  if not self.has_staged_issues:
533
592
  return []
@@ -539,10 +598,10 @@ class logger_t(base_t):
539
598
  else:
540
599
  separator = ISSUE_LEVEL_SEPARATOR
541
600
  separator_length = separator.__len__()
542
- for issue in self.staged_issues:
601
+ for issue, has_actual_expected in self.staged_issues:
543
602
  start_idx = issue.find(separator)
544
603
  issue = issue[(start_idx + separator_length) :]
545
- output.append(issue)
604
+ output.append((issue, has_actual_expected))
546
605
 
547
606
  self.staged_issues.clear()
548
607
 
@@ -564,13 +623,16 @@ class logger_t(base_t):
564
623
  "Invalid commit order",
565
624
  actual=order,
566
625
  expected=f"One of {str(ORDER)[1:-1]}",
567
- )
626
+ )[0]
568
627
  )
569
628
 
570
629
  if order == "when":
571
630
  issues = self.staged_issues
572
631
  else: # order == "context"
573
- issues = sorted(self.staged_issues, key=lambda _: _.context)
632
+ issues = sorted(
633
+ self.staged_issues,
634
+ key=lambda _: _[0].split(ISSUE_LEVEL_SEPARATOR, maxsplit=1)[1],
635
+ )
574
636
  """
575
637
  Format issues as an exception:
576
638
  try:
@@ -582,20 +644,43 @@ class logger_t(base_t):
582
644
  formatted = "\n".join(lines)
583
645
  """
584
646
 
585
- hide_where = {SHOW_WHERE_ATTR: False}
647
+ extra = {SHOW_WHERE_ATTR: False}
586
648
  if unified:
587
- level, _ = issues[0].split(ISSUE_LEVEL_SEPARATOR, maxsplit=1)
649
+ level, _ = issues[0][0].split(ISSUE_LEVEL_SEPARATOR, maxsplit=1)
588
650
  wo_level = []
589
- for issue in issues:
651
+ any_has_actual_expected = False
652
+ for issue, has_actual_expected in issues:
590
653
  _, issue = issue.split(ISSUE_LEVEL_SEPARATOR, maxsplit=1)
654
+ if has_actual_expected:
655
+ any_has_actual_expected = True
591
656
  wo_level.append(issue)
592
- self.log(int(level), "\n".join(wo_level), stacklevel=2, extra=hide_where)
657
+ if any_has_actual_expected:
658
+ extra[HAS_ACTUAL_EXPECTED_ATTR] = True
659
+ self.log(int(level), "\n".join(wo_level), stacklevel=2, extra=extra)
593
660
  else:
594
- for issue in issues:
661
+ for issue, has_actual_expected in issues:
595
662
  level, issue = issue.split(ISSUE_LEVEL_SEPARATOR, maxsplit=1)
596
- self.log(int(level), issue, stacklevel=2, extra=hide_where)
663
+ if has_actual_expected:
664
+ extra[HAS_ACTUAL_EXPECTED_ATTR] = True
665
+ self.log(int(level), issue, stacklevel=2, extra=extra)
666
+ if has_actual_expected:
667
+ del extra[HAS_ACTUAL_EXPECTED_ATTR]
597
668
  self.staged_issues.clear()
598
669
 
670
+ def StoragePath(self, suffix: str, /) -> path_t:
671
+ """
672
+ Use as staticmethod if needed.
673
+ """
674
+ for handler in self.handlers:
675
+ if (path := getattr(handler, "baseFilename", None)) is not None:
676
+ output = path_t(path).with_suffix(suffix)
677
+ if output.exists():
678
+ output = NewTemporaryFile(suffix)
679
+
680
+ return output
681
+
682
+ return NewTemporaryFile(suffix)
683
+
599
684
  def __enter__(self) -> None:
600
685
  """"""
601
686
  pass
@@ -611,6 +696,13 @@ class logger_t(base_t):
611
696
  _ = self.context_levels.pop()
612
697
  return False
613
698
 
699
+ def __del__(self) -> None:
700
+ """"""
701
+ assert prll.current_process().name == MAIN_PROCESS_NAME
702
+
703
+ if self.log_server is not None:
704
+ self.log_server.stop()
705
+
614
706
 
615
707
  def _HandleForWarnings(interceptor: base_t, /) -> logger_handle_h:
616
708
  """"""
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.24"
7
+ __version__ = "2025.25"
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.24
3
+ Version: 2025.25
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
@@ -109,46 +109,32 @@ The code is formatted by `Black <https://github.com/psf/black/>`_, *The Uncompro
109
109
  The imports are ordered by `isort <https://github.com/timothycrosley/isort/>`_... *your imports, so you don't have to*.
110
110
 
111
111
  ..
112
- COPYRIGHT NOTICE
113
-
114
- This software is governed by the CeCILL license under French law and
115
- abiding by the rules of distribution of free software. You can use,
116
- modify and/ or redistribute the software under the terms of the CeCILL
117
- license as circulated by CEA, CNRS and INRIA at the following URL
118
- "http://www.cecill.info".
119
-
120
- As a counterpart to the access to the source code and rights to copy,
121
- modify and redistribute granted by the license, users are provided only
122
- with a limited warranty and the software's author, the holder of the
123
- economic rights, and the successive licensors have only limited
124
- liability.
125
-
126
- In this respect, the user's attention is drawn to the risks associated
127
- with loading, using, modifying and/or developing or reproducing the
128
- software by the user in light of its specific status of free software,
129
- that may mean that it is complicated to manipulate, and that also
130
- therefore means that it is reserved for developers and experienced
131
- professionals having in-depth computer knowledge. Users are therefore
132
- encouraged to load and test the software's suitability as regards their
133
- requirements in conditions enabling the security of their systems and/or
134
- data to be ensured and, more generally, to use and operate it in the
135
- same conditions as regards security.
136
-
137
- The fact that you are presently reading this means that you have had
138
- knowledge of the CeCILL license and that you accept its terms.
139
-
140
- SEE LICENCE NOTICE: file README-LICENCE-utf8.txt at project source root.
141
-
142
- This software is being developed by Eric Debreuve, a CNRS employee and
143
- member of team Morpheme.
144
- Team Morpheme is a joint team between Inria, CNRS, and UniCA.
145
- It is hosted by the Centre Inria d'Université Côte d'Azur, Laboratory
146
- I3S, and Laboratory iBV.
147
-
148
- CNRS: https://www.cnrs.fr/index.php/en
149
- Inria: https://www.inria.fr/en/
150
- UniCA: https://univ-cotedazur.eu/
151
- Centre Inria d'Université Côte d'Azur: https://www.inria.fr/en/centre/sophia/
152
- I3S: https://www.i3s.unice.fr/en/
153
- iBV: http://ibv.unice.fr/
154
- Team Morpheme: https://team.inria.fr/morpheme/
112
+ COPYRIGHT NOTICE
113
+
114
+ This software is governed by the CeCILL license under French law and
115
+ abiding by the rules of distribution of free software. You can use,
116
+ modify and/ or redistribute the software under the terms of the CeCILL
117
+ license as circulated by CEA, CNRS and INRIA at the following URL
118
+ "http://www.cecill.info".
119
+
120
+ As a counterpart to the access to the source code and rights to copy,
121
+ modify and redistribute granted by the license, users are provided only
122
+ with a limited warranty and the software's author, the holder of the
123
+ economic rights, and the successive licensors have only limited
124
+ liability.
125
+
126
+ In this respect, the user's attention is drawn to the risks associated
127
+ with loading, using, modifying and/or developing or reproducing the
128
+ software by the user in light of its specific status of free software,
129
+ that may mean that it is complicated to manipulate, and that also
130
+ therefore means that it is reserved for developers and experienced
131
+ professionals having in-depth computer knowledge. Users are therefore
132
+ encouraged to load and test the software's suitability as regards their
133
+ requirements in conditions enabling the security of their systems and/or
134
+ data to be ensured and, more generally, to use and operate it in the
135
+ same conditions as regards security.
136
+
137
+ The fact that you are presently reading this means that you have had
138
+ knowledge of the CeCILL license and that you accept its terms.
139
+
140
+ SEE LICENCE NOTICE: file README-LICENCE-utf8.txt at project source root.
@@ -0,0 +1,53 @@
1
+ logger_36/__init__.py,sha256=mK6AD0eWI2Sk42oxleTvsxzYJ28FbHK5WNkpLgAhnNE,2129
2
+ logger_36/version.py,sha256=gqr9_xGceDfeDrDRv0O1e-8Rn6mXcEV_iFdCtiuTyAk,1680
3
+ logger_36/api/chronos.py,sha256=o_UMZbeExjb01aNURmzIjOMAHhI9e90nyvJJYcJR6VQ,1739
4
+ logger_36/api/logger.py,sha256=eLZ2yuH-sYeh4Z2KnAwTRJEbmkmgzBPMncdqXfFUTG8,1760
5
+ logger_36/api/memory.py,sha256=U4mMEkx8WRHk9q2d3SCFGt2EJaBuflOXw2bGbAxOnSc,1828
6
+ logger_36/api/message.py,sha256=DuT4UX4r_1DTXzuuRD-tvsTZk5X-Nj11loBKhuWOMw0,1791
7
+ logger_36/api/storage.py,sha256=S1fVzrMp-_zlhg27fRPddWCFQRyvbpFwSreALOeoNFI,1713
8
+ logger_36/catalog/config/console_rich.py,sha256=t9p9-AkSgPiLAsm1evAdbz77g7JcVLePhUJ1FzNi3cY,2330
9
+ logger_36/catalog/config/optional.py,sha256=8d8HdpE07gHfsdoL8mVAlRlh9AgLcb4z7I7h6ob7CfU,2174
10
+ logger_36/catalog/handler/console.py,sha256=XIyO_8MrzaTlihDbFhIzRk47HjxMH4gV2Zqp0-1oMsU,2320
11
+ logger_36/catalog/handler/console_rich.py,sha256=RXLu8AQxAmyec1bXUc99Mabp7BjZc-lKEfwrCzMPkZA,6662
12
+ logger_36/catalog/handler/file.py,sha256=5GR_aACDEBXuZ-pUH9P0OCaXbCf-aLPmsz-XrGCAIgE,2434
13
+ logger_36/catalog/handler/generic.py,sha256=kwr7x7GWLmWvT7niHGW7OqlMotvTQNuNEwQGfKh_nhU,7040
14
+ logger_36/catalog/handler/memory.py,sha256=pJwKOlCm8Ej8ipDI00-FfX4qJjMPXJb-DucD1ukIQOU,4057
15
+ logger_36/catalog/logger/chronos.py,sha256=MDAx_NRRcRZcQYDDjVCRcu87SDP-rPYjX0-10KNcMnk,2216
16
+ logger_36/catalog/logger/gpu.py,sha256=Py5YY0nD_pqJzJsEKQYoOGHcPqyNVJ3J2noOS3hDL6g,2890
17
+ logger_36/catalog/logger/memory.py,sha256=pa-9pkvDGdf52giwL3Zi1mjWNFE_NVzBGdjwcfeIDNc,4256
18
+ logger_36/catalog/logger/system.py,sha256=zEbHirATqZAVYFmHLd0pppeuRhka1ucWwyHRq0afQNE,2593
19
+ logger_36/config/issue.py,sha256=QOkVRPSLZC_2mfcFpad-pcSXJXfLHdWUAXiMbTWlZTg,1741
20
+ logger_36/config/memory.py,sha256=bZmNYsD2goVdkraS1v_t2OqAJo86jKMtP311kIVURDk,1691
21
+ logger_36/config/message.py,sha256=bDAW4hZdsHBTYlCA7IZbL1FxGPwjX9Khmw0d21VHGs0,1968
22
+ logger_36/config/rule.py,sha256=BqOb4SWKgT0YQZ-DtOzkLNZNWZVZkl5GN3lMoWoPrKw,1702
23
+ logger_36/config/system.py,sha256=YRSa2eN_SoTnTXWUXAcpKt4JXifabzMR0eXwjUYlA_A,1951
24
+ logger_36/constant/chronos.py,sha256=JJvBN_skqRdUgnuWhMqG0gZ3_ZkXmAz1syEixfu4lCM,2131
25
+ logger_36/constant/error.py,sha256=FinnCcwGGH2oiXX3aw2uxKYvR3d5Tkb9rlNhNjyuoF8,2354
26
+ logger_36/constant/html.py,sha256=w8gttc1XBSMpdKRolnXAVJ5x_hOAIsVsUyELCXJYdWU,2011
27
+ logger_36/constant/issue.py,sha256=0EmcsRmSxktFUJR0qOU0PnKG-gfbLDOULH6sSRHFOcc,1789
28
+ logger_36/constant/logger.py,sha256=ZQYX9JiPsoivwRgYNtdEqRKCagSKD88lRqvxP8MX1ZE,1942
29
+ logger_36/constant/memory.py,sha256=Q_E5tTWa-cGaNwrE_xmKa3BxQG6oJO6DHczrxc_M4sE,1817
30
+ logger_36/constant/message.py,sha256=TdsZXWO2UmlG3a0ia3UsUCxtVUa8GNferi69pO4A9TM,2301
31
+ logger_36/constant/path.py,sha256=r-vx5ztGhcpYfg37kw0oaxBYdTSkWOJuToTmexaW8tE,2265
32
+ logger_36/constant/record.py,sha256=70JO2LYL-1Eg-vLD3N7nUoYALp6ji7-b3DLxCHTc7iQ,1881
33
+ logger_36/constant/rule.py,sha256=ul-MqOdHBGBC5Nwn05EUnz2T__7VEs82qiH7Fzs5qCk,1804
34
+ logger_36/constant/system.py,sha256=pLlLXG5sepQlSUOo3TphaGrHg8xzJBp-GxpL2NPP47k,1904
35
+ logger_36/extension/file.py,sha256=ClY8k805DnB6Vy0LEQIhlO0MavP91Y-CEjHjFepyROE,2034
36
+ logger_36/extension/inspection.py,sha256=LoHXi4wsIgHKrq_7GYkVcfJ9rnBG16pLKMpAoHNwJiY,3922
37
+ logger_36/extension/line.py,sha256=9BgxnY6wiyc44Ari5rkvqbvz9ao4sNs39u8k7sY6vFc,2611
38
+ logger_36/extension/sentinel.py,sha256=SQgkQiRcTIjCRvbxiOb6TEm59BC0FNMcjYoIShpcwLo,1718
39
+ logger_36/instance/logger.py,sha256=X_U10RYU1h2Aa70D8hBnmFyJZtRILK16KN-GB4xkHMU,1782
40
+ logger_36/instance/loggers.py,sha256=inBk4KKrQ-z3szaopQ29-qQwh1iSc842sWo5J6zJoiM,1725
41
+ logger_36/task/storage.py,sha256=L93v5w9p_7MoiagEr3d6QSYEQxX42DxmZ-BJTCuLpgQ,3915
42
+ logger_36/task/format/memory.py,sha256=xcWwbUnl1BxH7RVBHyhp1RlbT2n370PzoFLLLd3dtlU,3726
43
+ logger_36/task/format/message.py,sha256=Q9QkyUAU47Nj606zsvq0gNyso8Vk9G9OaqG9Em5FjKg,3575
44
+ logger_36/task/measure/chronos.py,sha256=fZKK16LwlLzRRAP-gfF1uy6gFCL33gR7LZ4Xs_nXdVY,2612
45
+ logger_36/task/measure/memory.py,sha256=kkPHEIUTUhkCOLrAt01eLJLnsnkl0nFPNhFZdIB_JAw,1991
46
+ logger_36/type/handler.py,sha256=bDsCFYpevCJBV7Vc9jovttapjU-7GXI1_TDbmOf2kN4,6660
47
+ logger_36/type/issue.py,sha256=M2KeQwzDG9yqgdtbyWk5Y-ier7c71TuAKlNCf5QCGzY,2770
48
+ logger_36/type/logger.py,sha256=0OjqyMcBAyS0qUUeEzweALrs0m5rVqZF3e6R1b8B4RA,27358
49
+ logger_36/type/loggers.py,sha256=7EX7Sg_RlduBjdfFlNZmUfNeDloH1xU30Rdkg_-rXh8,3172
50
+ logger_36-2025.25.dist-info/METADATA,sha256=Uchfn7mGuqLow-qAR-TejGvwkXNns2N7XnpLbgHeGFE,5980
51
+ logger_36-2025.25.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
52
+ logger_36-2025.25.dist-info/top_level.txt,sha256=sM95BTMWmslEEgR_1pzwZsOeSp8C_QBiu8ImbFr0XLc,10
53
+ logger_36-2025.25.dist-info/RECORD,,