logger-36 2025.24__tar.gz → 2025.26__tar.gz

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.
Files changed (63) hide show
  1. {logger_36-2025.24 → logger_36-2025.26}/PKG-INFO +30 -44
  2. {logger_36-2025.24 → logger_36-2025.26}/README.rst +29 -43
  3. logger_36-2025.24/package/logger_36/api/time.py → logger_36-2025.26/package/logger_36/api/chronos.py +1 -1
  4. {logger_36-2025.24 → logger_36-2025.26}/package/logger_36/catalog/handler/console_rich.py +39 -29
  5. {logger_36-2025.24 → logger_36-2025.26}/package/logger_36/catalog/handler/file.py +1 -2
  6. {logger_36-2025.24 → logger_36-2025.26}/package/logger_36/catalog/handler/generic.py +24 -10
  7. {logger_36-2025.24 → logger_36-2025.26}/package/logger_36/catalog/handler/memory.py +24 -2
  8. logger_36-2025.26/package/logger_36/catalog/logger/chronos.py +55 -0
  9. {logger_36-2025.24 → logger_36-2025.26}/package/logger_36/catalog/logger/memory.py +1 -1
  10. {logger_36-2025.24 → logger_36-2025.26}/package/logger_36/config/message.py +1 -4
  11. logger_36-2025.24/package/logger_36/constant/date_time.py → logger_36-2025.26/package/logger_36/constant/chronos.py +4 -0
  12. {logger_36-2025.24 → logger_36-2025.26}/package/logger_36/constant/error.py +2 -0
  13. {logger_36-2025.24 → logger_36-2025.26}/package/logger_36/constant/html.py +2 -0
  14. {logger_36-2025.24 → logger_36-2025.26}/package/logger_36/constant/message.py +7 -7
  15. {logger_36-2025.24 → logger_36-2025.26}/package/logger_36/constant/record.py +2 -0
  16. logger_36-2025.24/package/logger_36/catalog/logger/chronos.py → logger_36-2025.26/package/logger_36/extension/file.py +14 -5
  17. {logger_36-2025.24 → logger_36-2025.26}/package/logger_36/extension/line.py +1 -3
  18. {logger_36-2025.24 → logger_36-2025.26}/package/logger_36/task/format/memory.py +1 -1
  19. {logger_36-2025.24 → logger_36-2025.26}/package/logger_36/task/format/message.py +7 -5
  20. {logger_36-2025.24 → logger_36-2025.26}/package/logger_36/task/measure/chronos.py +21 -11
  21. {logger_36-2025.24 → logger_36-2025.26}/package/logger_36/task/storage.py +30 -55
  22. {logger_36-2025.24 → logger_36-2025.26}/package/logger_36/type/handler.py +22 -24
  23. {logger_36-2025.24 → logger_36-2025.26}/package/logger_36/type/issue.py +7 -4
  24. {logger_36-2025.24 → logger_36-2025.26}/package/logger_36/type/logger.py +157 -51
  25. {logger_36-2025.24 → logger_36-2025.26}/package/logger_36/type/loggers.py +0 -2
  26. {logger_36-2025.24 → logger_36-2025.26}/package/logger_36/version.py +1 -1
  27. {logger_36-2025.24 → logger_36-2025.26}/package/logger_36.egg-info/PKG-INFO +30 -44
  28. {logger_36-2025.24 → logger_36-2025.26}/package/logger_36.egg-info/SOURCES.txt +4 -4
  29. logger_36-2025.24/package/logger_36/extension/record.py +0 -66
  30. {logger_36-2025.24 → logger_36-2025.26}/MANIFEST.in +0 -0
  31. {logger_36-2025.24 → logger_36-2025.26}/README-COPYRIGHT-utf8.txt +0 -0
  32. {logger_36-2025.24 → logger_36-2025.26}/README-LICENCE-utf8.txt +0 -0
  33. {logger_36-2025.24 → logger_36-2025.26}/documentation/wiki/description.asciidoc +0 -0
  34. {logger_36-2025.24 → logger_36-2025.26}/package/logger_36/__init__.py +0 -0
  35. {logger_36-2025.24 → logger_36-2025.26}/package/logger_36/api/logger.py +0 -0
  36. {logger_36-2025.24 → logger_36-2025.26}/package/logger_36/api/memory.py +0 -0
  37. {logger_36-2025.24 → logger_36-2025.26}/package/logger_36/api/message.py +0 -0
  38. {logger_36-2025.24 → logger_36-2025.26}/package/logger_36/api/storage.py +0 -0
  39. {logger_36-2025.24 → logger_36-2025.26}/package/logger_36/catalog/config/console_rich.py +0 -0
  40. {logger_36-2025.24 → logger_36-2025.26}/package/logger_36/catalog/config/optional.py +0 -0
  41. {logger_36-2025.24 → logger_36-2025.26}/package/logger_36/catalog/handler/console.py +0 -0
  42. {logger_36-2025.24 → logger_36-2025.26}/package/logger_36/catalog/logger/gpu.py +0 -0
  43. {logger_36-2025.24 → logger_36-2025.26}/package/logger_36/catalog/logger/system.py +0 -0
  44. {logger_36-2025.24 → logger_36-2025.26}/package/logger_36/config/issue.py +0 -0
  45. {logger_36-2025.24 → logger_36-2025.26}/package/logger_36/config/memory.py +0 -0
  46. {logger_36-2025.24 → logger_36-2025.26}/package/logger_36/config/rule.py +0 -0
  47. {logger_36-2025.24 → logger_36-2025.26}/package/logger_36/config/system.py +0 -0
  48. {logger_36-2025.24 → logger_36-2025.26}/package/logger_36/constant/issue.py +0 -0
  49. {logger_36-2025.24 → logger_36-2025.26}/package/logger_36/constant/logger.py +0 -0
  50. {logger_36-2025.24 → logger_36-2025.26}/package/logger_36/constant/memory.py +0 -0
  51. {logger_36-2025.24 → logger_36-2025.26}/package/logger_36/constant/path.py +0 -0
  52. {logger_36-2025.24 → logger_36-2025.26}/package/logger_36/constant/rule.py +0 -0
  53. {logger_36-2025.24 → logger_36-2025.26}/package/logger_36/constant/system.py +0 -0
  54. {logger_36-2025.24 → logger_36-2025.26}/package/logger_36/extension/inspection.py +0 -0
  55. /logger_36-2025.24/package/logger_36/constant/generic.py → /logger_36-2025.26/package/logger_36/extension/sentinel.py +0 -0
  56. {logger_36-2025.24 → logger_36-2025.26}/package/logger_36/instance/logger.py +0 -0
  57. {logger_36-2025.24 → logger_36-2025.26}/package/logger_36/instance/loggers.py +0 -0
  58. {logger_36-2025.24 → logger_36-2025.26}/package/logger_36/task/measure/memory.py +0 -0
  59. {logger_36-2025.24 → logger_36-2025.26}/package/logger_36.egg-info/dependency_links.txt +0 -0
  60. {logger_36-2025.24 → logger_36-2025.26}/package/logger_36.egg-info/top_level.txt +0 -0
  61. {logger_36-2025.24 → logger_36-2025.26}/pyproject.toml +0 -0
  62. {logger_36-2025.24 → logger_36-2025.26}/setup.cfg +0 -0
  63. {logger_36-2025.24 → logger_36-2025.26}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: logger-36
3
- Version: 2025.24
3
+ Version: 2025.26
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.
@@ -79,46 +79,32 @@ The code is formatted by `Black <https://github.com/psf/black/>`_, *The Uncompro
79
79
  The imports are ordered by `isort <https://github.com/timothycrosley/isort/>`_... *your imports, so you don't have to*.
80
80
 
81
81
  ..
82
- COPYRIGHT NOTICE
83
-
84
- This software is governed by the CeCILL license under French law and
85
- abiding by the rules of distribution of free software. You can use,
86
- modify and/ or redistribute the software under the terms of the CeCILL
87
- license as circulated by CEA, CNRS and INRIA at the following URL
88
- "http://www.cecill.info".
89
-
90
- As a counterpart to the access to the source code and rights to copy,
91
- modify and redistribute granted by the license, users are provided only
92
- with a limited warranty and the software's author, the holder of the
93
- economic rights, and the successive licensors have only limited
94
- liability.
95
-
96
- In this respect, the user's attention is drawn to the risks associated
97
- with loading, using, modifying and/or developing or reproducing the
98
- software by the user in light of its specific status of free software,
99
- that may mean that it is complicated to manipulate, and that also
100
- therefore means that it is reserved for developers and experienced
101
- professionals having in-depth computer knowledge. Users are therefore
102
- encouraged to load and test the software's suitability as regards their
103
- requirements in conditions enabling the security of their systems and/or
104
- data to be ensured and, more generally, to use and operate it in the
105
- same conditions as regards security.
106
-
107
- The fact that you are presently reading this means that you have had
108
- knowledge of the CeCILL license and that you accept its terms.
109
-
110
- SEE LICENCE NOTICE: file README-LICENCE-utf8.txt at project source root.
111
-
112
- This software is being developed by Eric Debreuve, a CNRS employee and
113
- member of team Morpheme.
114
- Team Morpheme is a joint team between Inria, CNRS, and UniCA.
115
- It is hosted by the Centre Inria d'Université Côte d'Azur, Laboratory
116
- I3S, and Laboratory iBV.
117
-
118
- CNRS: https://www.cnrs.fr/index.php/en
119
- Inria: https://www.inria.fr/en/
120
- UniCA: https://univ-cotedazur.eu/
121
- Centre Inria d'Université Côte d'Azur: https://www.inria.fr/en/centre/sophia/
122
- I3S: https://www.i3s.unice.fr/en/
123
- iBV: http://ibv.unice.fr/
124
- Team Morpheme: https://team.inria.fr/morpheme/
82
+ COPYRIGHT NOTICE
83
+
84
+ This software is governed by the CeCILL license under French law and
85
+ abiding by the rules of distribution of free software. You can use,
86
+ modify and/ or redistribute the software under the terms of the CeCILL
87
+ license as circulated by CEA, CNRS and INRIA at the following URL
88
+ "http://www.cecill.info".
89
+
90
+ As a counterpart to the access to the source code and rights to copy,
91
+ modify and redistribute granted by the license, users are provided only
92
+ with a limited warranty and the software's author, the holder of the
93
+ economic rights, and the successive licensors have only limited
94
+ liability.
95
+
96
+ In this respect, the user's attention is drawn to the risks associated
97
+ with loading, using, modifying and/or developing or reproducing the
98
+ software by the user in light of its specific status of free software,
99
+ that may mean that it is complicated to manipulate, and that also
100
+ therefore means that it is reserved for developers and experienced
101
+ professionals having in-depth computer knowledge. Users are therefore
102
+ encouraged to load and test the software's suitability as regards their
103
+ requirements in conditions enabling the security of their systems and/or
104
+ data to be ensured and, more generally, to use and operate it in the
105
+ same conditions as regards security.
106
+
107
+ The fact that you are presently reading this means that you have had
108
+ knowledge of the CeCILL license and that you accept its terms.
109
+
110
+ SEE LICENCE NOTICE: file README-LICENCE-utf8.txt at project source root.
@@ -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
- from logger_36.task.measure.chronos import ElapsedTime, TimeStamp # noqa
7
+ from logger_36.task.measure.chronos import FormattedElapsedTime, TimeStamp # noqa
8
8
 
9
9
  """
10
10
  COPYRIGHT NOTICE
@@ -7,13 +7,6 @@ SEE COPYRIGHT NOTICE BELOW
7
7
  import logging as l
8
8
  import typing as h
9
9
 
10
- from rich.console import Console as console_t # noqa
11
- from rich.console import RenderableType as renderable_t # noqa
12
- from rich.markup import escape as EscapedVersion # noqa
13
- from rich.rule import Rule as rule_t # noqa
14
- from rich.text import Text as text_t # noqa
15
- from rich.traceback import install as InstallTracebackHandler # noqa
16
-
17
10
  from logger_36.catalog.config.console_rich import (
18
11
  ACTUAL_COLOR,
19
12
  ALTERNATIVE_BACKGROUND_FOR_DARK,
@@ -24,9 +17,17 @@ from logger_36.catalog.config.console_rich import (
24
17
  RULE_COLOR,
25
18
  WHITE_COLOR,
26
19
  )
27
- from logger_36.config.message import ACTUAL_PATTERNS, EXPECTED_PATTERNS, WHERE_SEPARATOR
20
+ from logger_36.config.message import ACTUAL_PATTERNS, EXPECTED_PATTERNS
28
21
  from logger_36.constant.message import CONTEXT_LENGTH
22
+ from logger_36.constant.record import HAS_ACTUAL_EXPECTED_ATTR
29
23
  from logger_36.type.handler import non_file_handler_t as base_t
24
+ from rich.console import Console as console_t # noqa
25
+ from rich.console import RenderableType as renderable_t # noqa
26
+ from rich.markup import escape as EscapedVersion # noqa
27
+ from rich.rule import Rule as rule_t # noqa
28
+ from rich.style import Style as style_t # noqa
29
+ from rich.text import Text as text_t # noqa
30
+ from rich.traceback import install as InstallTracebackHandler # noqa
30
31
 
31
32
  _COMMON_TRACEBACK_ARGUMENTS = ("theme", "width")
32
33
  _EXCLUSIVE_TRACEBACK_ARGUMENTS = (
@@ -62,8 +63,13 @@ class console_rich_handler_t(base_t):
62
63
  base_t.__init__(self, name, message_width, EscapedVersion, level, kwargs)
63
64
 
64
65
  self.console = None # console_t | None.
65
- self.alternating_logs = alternating_logs
66
- self._log_parity = False
66
+ if alternating_logs == 0:
67
+ self.background_style = None
68
+ elif alternating_logs == 1:
69
+ self.background_style = ALTERNATIVE_BACKGROUND_FOR_DARK
70
+ else:
71
+ self.background_style = ALTERNATIVE_BACKGROUND_FOR_LIGHT
72
+ self._should_style_background = False
67
73
 
68
74
  self.__post_init_local__(should_install_traceback, **kwargs)
69
75
 
@@ -98,23 +104,30 @@ class console_rich_handler_t(base_t):
98
104
 
99
105
  def Rule(self, /, *, text: str | None = None, color: str = "black") -> str | rule_t:
100
106
  """"""
101
- if text is None:
107
+ if text in (None, ""):
102
108
  return rule_t(style=color)
103
109
  return rule_t(title=text_t(text, style=f"bold {color}"), style=color)
104
110
 
105
111
  def emit(self, record: l.LogRecord, /) -> None:
106
112
  """"""
107
- message, is_not_a_rule = self.MessageFromRecord(record, rule_color=RULE_COLOR)
113
+ message, is_not_a_rule, where_location = self.MessageFromRecord(
114
+ record, rule_color=RULE_COLOR
115
+ )
108
116
  if is_not_a_rule:
117
+ if self._should_style_background:
118
+ background_style = self.background_style
119
+ else:
120
+ background_style = None
109
121
  message = HighlightedVersion(
110
122
  self.console,
111
123
  message,
124
+ getattr(record, HAS_ACTUAL_EXPECTED_ATTR, False),
125
+ where_location,
112
126
  record.levelno,
113
- self.alternating_logs,
114
- self._log_parity,
127
+ background_style,
115
128
  )
116
129
  self.console.print(message, crop=False, overflow="ignore")
117
- self._log_parity = not self._log_parity
130
+ self._should_style_background = not self._should_style_background
118
131
 
119
132
  def EmitMessage(self, message: str | renderable_t, /) -> None:
120
133
  """"""
@@ -124,27 +137,24 @@ class console_rich_handler_t(base_t):
124
137
  def HighlightedVersion(
125
138
  _: console_t,
126
139
  message: str,
140
+ has_actual_expected: bool,
141
+ where_location: int | None,
127
142
  log_level: int,
128
- alternating_logs: int,
129
- should_tint_background: bool,
143
+ background_style: style_t | None,
130
144
  /,
131
145
  ) -> renderable_t:
132
146
  """"""
133
147
  output = text_t(message, WHITE_COLOR)
134
148
 
135
149
  output.stylize(LEVEL_COLOR[log_level], end=CONTEXT_LENGTH)
136
- where = message.rfind(WHERE_SEPARATOR)
137
- if (where >= 0) and ("\n" not in message[where:]):
138
- output.stylize(GRAY_COLOR, start=where)
139
- _ = output.highlight_words(ACTUAL_PATTERNS, style=ACTUAL_COLOR)
140
- _ = output.highlight_regex(EXPECTED_PATTERNS, style=EXPECTED_COLOR)
141
-
142
- if should_tint_background and (alternating_logs > 0):
143
- if alternating_logs == 1:
144
- style = ALTERNATIVE_BACKGROUND_FOR_DARK
145
- else:
146
- style = ALTERNATIVE_BACKGROUND_FOR_LIGHT
147
- output.stylize(style)
150
+ if where_location is not None:
151
+ output.stylize(GRAY_COLOR, start=where_location)
152
+ if has_actual_expected:
153
+ _ = output.highlight_words(ACTUAL_PATTERNS, style=ACTUAL_COLOR)
154
+ _ = output.highlight_regex(EXPECTED_PATTERNS, style=EXPECTED_COLOR)
155
+
156
+ if background_style is not None:
157
+ output.stylize(background_style)
148
158
 
149
159
  return output
150
160
 
@@ -28,8 +28,7 @@ class file_handler_t(base_t):
28
28
 
29
29
  def emit(self, record: l.LogRecord, /) -> None:
30
30
  """"""
31
- output = self.MessageFromRecord(record)
32
- self.stream.write(output[0] + "\n")
31
+ self.stream.write(self.MessageFromRecord(record)[0] + "\n")
33
32
  self.stream.flush()
34
33
 
35
34
  def EmitMessage(self, message: str, /) -> None:
@@ -8,16 +8,20 @@ import logging as l
8
8
  import typing as h
9
9
 
10
10
  from logger_36.catalog.config.optional import RICH_IS_AVAILABLE
11
+ from logger_36.constant.record import HAS_ACTUAL_EXPECTED_ATTR
11
12
 
12
13
  if RICH_IS_AVAILABLE:
14
+ from logger_36.catalog.config.console_rich import (
15
+ ALTERNATIVE_BACKGROUND_FOR_DARK,
16
+ ALTERNATIVE_BACKGROUND_FOR_LIGHT,
17
+ RULE_COLOR,
18
+ )
19
+ from logger_36.catalog.handler.console_rich import HighlightedVersion
13
20
  from rich.console import Console as console_t
14
21
  from rich.markup import escape as EscapedForRich
15
22
  from rich.rule import Rule as rule_t
16
23
  from rich.terminal_theme import DEFAULT_TERMINAL_THEME
17
24
  from rich.text import Text as text_t
18
-
19
- from logger_36.catalog.config.console_rich import RULE_COLOR
20
- from logger_36.catalog.handler.console_rich import HighlightedVersion
21
25
  else:
22
26
  console_t = EscapedForRich = rule_t = DEFAULT_TERMINAL_THEME = text_t = (
23
27
  RULE_COLOR
@@ -54,8 +58,13 @@ class generic_handler_t(base_t):
54
58
  self.is_rich = False
55
59
  self.console = None # console_t | None.
56
60
  self.console_options = None # rich.console.ConsoleOptions | None.
57
- self.alternating_logs = alternating_logs
58
- self._log_parity = False
61
+ if alternating_logs == 0:
62
+ self.background_style = None
63
+ elif alternating_logs == 1:
64
+ self.background_style = ALTERNATIVE_BACKGROUND_FOR_DARK
65
+ else:
66
+ self.background_style = ALTERNATIVE_BACKGROUND_FOR_LIGHT
67
+ self._should_style_background = False
59
68
 
60
69
  self.__post_init_local__(supports_html)
61
70
 
@@ -85,7 +94,7 @@ class generic_handler_t(base_t):
85
94
  def Rule(self, /, *, text: str | None = None, color: str = "black") -> str | rule_t:
86
95
  """"""
87
96
  if self.is_rich:
88
- if text is None:
97
+ if text in (None, ""):
89
98
  return rule_t(style=color)
90
99
  return rule_t(title=text_t(text, style=f"bold {color}"), style=color)
91
100
 
@@ -94,16 +103,21 @@ class generic_handler_t(base_t):
94
103
  def emit(self, record: l.LogRecord, /) -> None:
95
104
  """"""
96
105
  if self.is_rich:
97
- message, is_not_a_rule = self.MessageFromRecord(
106
+ message, is_not_a_rule, where_location = self.MessageFromRecord(
98
107
  record, rule_color=RULE_COLOR
99
108
  )
100
109
  if is_not_a_rule:
110
+ if self._should_style_background:
111
+ background_style = self.background_style
112
+ else:
113
+ background_style = None
101
114
  message = HighlightedVersion(
102
115
  self.console,
103
116
  message,
117
+ getattr(record, HAS_ACTUAL_EXPECTED_ATTR, False),
118
+ where_location,
104
119
  record.levelno,
105
- self.alternating_logs,
106
- self._log_parity,
120
+ background_style,
107
121
  )
108
122
  segments = self.console.render(message, options=self.console_options)
109
123
 
@@ -132,7 +146,7 @@ class generic_handler_t(base_t):
132
146
  message = self.MessageFromRecord(record)[0]
133
147
 
134
148
  self.EmitMessage(message)
135
- self._log_parity = not self._log_parity
149
+ self._should_style_background = not self._should_style_background
136
150
 
137
151
 
138
152
  """
@@ -12,6 +12,10 @@ from logger_36.type.handler import non_file_handler_t as base_t
12
12
 
13
13
  formats_h = h.Literal["dict", "json", "message", "raw"]
14
14
 
15
+ record_raw_h = dict | str | l.LogRecord
16
+ record_h = tuple[int, record_raw_h, bool] # level, [...], is_not_a_rule.
17
+ records_h = list[record_h]
18
+
15
19
 
16
20
  class memory_handler_t(base_t):
17
21
  def __init__(
@@ -23,7 +27,7 @@ class memory_handler_t(base_t):
23
27
  base_t.__init__(self, name, message_width, None, level)
24
28
 
25
29
  self.format_ = format_
26
- self.records = []
30
+ self.records: records_h = []
27
31
 
28
32
  @classmethod
29
33
  def New(
@@ -52,7 +56,7 @@ class memory_handler_t(base_t):
52
56
  record = json.dumps(record.__dict__)
53
57
  is_not_a_rule = True
54
58
  else:
55
- record, is_not_a_rule = self.MessageFromRecord(record)
59
+ record, is_not_a_rule, _ = self.MessageFromRecord(record)
56
60
 
57
61
  self.records.append((level, record, is_not_a_rule))
58
62
 
@@ -67,6 +71,24 @@ class memory_handler_t(base_t):
67
71
  )
68
72
  self.emit(record)
69
73
 
74
+ @staticmethod
75
+ def IsRecord(checked: h.Any, /) -> bool:
76
+ """"""
77
+ return (
78
+ isinstance(checked, tuple)
79
+ and (checked.__len__() == 3)
80
+ and isinstance(checked[0], int)
81
+ and isinstance(checked[1], record_raw_h)
82
+ and isinstance(checked[2], bool)
83
+ )
84
+
85
+ @classmethod
86
+ def AreRecords(cls, checked: h.Any, /) -> bool:
87
+ """"""
88
+ return isinstance(checked, list | tuple) and (
89
+ (checked.__len__() == 0) or all(map(cls.IsRecord, checked))
90
+ )
91
+
70
92
 
71
93
  """
72
94
  COPYRIGHT NOTICE
@@ -0,0 +1,55 @@
1
+ """
2
+ Copyright CNRS (https://www.cnrs.fr/index.php/en)
3
+ Contributor(s): Eric Debreuve (eric.debreuve@cnrs.fr) since 2023
4
+ SEE COPYRIGHT NOTICE BELOW
5
+ """
6
+
7
+ from datetime import datetime as date_time_t
8
+
9
+ from logger_36.constant.chronos import FORMATTED_START_DATE_TIME
10
+ from logger_36.constant.record import SHOW_WHEN_ATTR
11
+ from logger_36.instance.logger import L
12
+ from logger_36.task.measure.chronos import FormattedElapsedTime
13
+ from logger_36.type.logger import logger_t
14
+
15
+
16
+ def LogElapsedTime(*, logger: logger_t = L) -> None:
17
+ """"""
18
+ logger.info(
19
+ f"Elapsed Time: {FormattedElapsedTime(date_time_t.now())[1:]} "
20
+ f"(since {FORMATTED_START_DATE_TIME})",
21
+ extra={SHOW_WHEN_ATTR: False},
22
+ )
23
+
24
+
25
+ """
26
+ COPYRIGHT NOTICE
27
+
28
+ This software is governed by the CeCILL license under French law and
29
+ abiding by the rules of distribution of free software. You can use,
30
+ modify and/ or redistribute the software under the terms of the CeCILL
31
+ license as circulated by CEA, CNRS and INRIA at the following URL
32
+ "http://www.cecill.info".
33
+
34
+ As a counterpart to the access to the source code and rights to copy,
35
+ modify and redistribute granted by the license, users are provided only
36
+ with a limited warranty and the software's author, the holder of the
37
+ economic rights, and the successive licensors have only limited
38
+ liability.
39
+
40
+ In this respect, the user's attention is drawn to the risks associated
41
+ with loading, using, modifying and/or developing or reproducing the
42
+ software by the user in light of its specific status of free software,
43
+ that may mean that it is complicated to manipulate, and that also
44
+ therefore means that it is reserved for developers and experienced
45
+ professionals having in-depth computer knowledge. Users are therefore
46
+ encouraged to load and test the software's suitability as regards their
47
+ requirements in conditions enabling the security of their systems and/or
48
+ data to be ensured and, more generally, to use and operate it in the
49
+ same conditions as regards security.
50
+
51
+ The fact that you are presently reading this means that you have had
52
+ knowledge of the CeCILL license and that you accept its terms.
53
+
54
+ SEE LICENCE NOTICE: file README-LICENCE-utf8.txt at project source root.
55
+ """
@@ -38,7 +38,7 @@ def LogMemoryUsages(
38
38
  actual=max_n_samples,
39
39
  expected=1,
40
40
  expected_op=">=",
41
- )
41
+ )[0]
42
42
  )
43
43
 
44
44
  where_s = list(where_s)
@@ -6,12 +6,9 @@ SEE COPYRIGHT NOTICE BELOW
6
6
 
7
7
  from datetime import timedelta as time_delta_t
8
8
 
9
- LEVEL_OPENING = "("
10
- LEVEL_CLOSING = ")"
11
- MESSAGE_MARKER = "|"
12
9
  WHERE_SEPARATOR = "@"
13
10
  ELAPSED_TIME_SEPARATOR = "+"
14
- FALLBACK_MESSAGE_WIDTH = 5
11
+ FALLBACK_MESSAGE_WIDTH = 20
15
12
 
16
13
  DATE_FORMAT = "%Y-%m-%d"
17
14
  TIME_FORMAT = "%H:%M:%S"
@@ -6,10 +6,14 @@ SEE COPYRIGHT NOTICE BELOW
6
6
 
7
7
  from datetime import datetime as date_time_t
8
8
 
9
+ from logger_36.config.message import DATE_FORMAT, TIME_FORMAT
10
+
9
11
  # This module is imported early. Therefore, the current date and time should be close
10
12
  # enough to the real start date and time of the main script.
11
13
  START_DATE_TIME = date_time_t.now()
12
14
 
15
+ FORMATTED_START_DATE_TIME = f"{START_DATE_TIME:{TIME_FORMAT + ' on ' + DATE_FORMAT}}"
16
+
13
17
  DATE_TIME_ORIGIN = date_time_t.fromtimestamp(1970, None)
14
18
  DATE_ORIGIN = DATE_TIME_ORIGIN.date()
15
19
 
@@ -23,6 +23,8 @@ MISSING_RICH_MESSAGE = (
23
23
  "Falling back to the raw console."
24
24
  )
25
25
 
26
+ CANNOT_SAVE_RECORDS = "Cannot save logging records"
27
+
26
28
  """
27
29
  COPYRIGHT NOTICE
28
30
 
@@ -22,6 +22,8 @@ MINIMAL_HTML = f"""
22
22
  </html>
23
23
  """
24
24
 
25
+ HTML_SUFFIX = ".htm"
26
+
25
27
 
26
28
  """
27
29
  COPYRIGHT NOTICE
@@ -9,18 +9,18 @@ import typing as h
9
9
 
10
10
  from logger_36.config.message import (
11
11
  ELAPSED_TIME_SEPARATOR,
12
- LEVEL_CLOSING,
13
- LEVEL_OPENING,
14
- MESSAGE_MARKER,
15
12
  TIME_FORMAT,
13
+ WHERE_SEPARATOR,
16
14
  )
17
15
 
18
16
  TIME_LENGTH = time.strftime(TIME_FORMAT, time.gmtime(0)).__len__()
19
- TIME_LENGTH_m_1 = TIME_LENGTH - ELAPSED_TIME_SEPARATOR.__len__()
20
- LOG_LEVEL_LENGTH = 1 + LEVEL_OPENING.__len__() + LEVEL_CLOSING.__len__()
21
- CONTEXT_LENGTH = TIME_LENGTH + LOG_LEVEL_LENGTH
22
- LINE_INDENT = (CONTEXT_LENGTH + MESSAGE_MARKER.__len__() + 2) * " "
17
+ CONTEXT_LENGTH = TIME_LENGTH + 2 # 2=<underscore><level name first letter>.
18
+ CONTEXT_LENGTH_p_1 = CONTEXT_LENGTH + 1
19
+ LINE_INDENT = (CONTEXT_LENGTH + 1) * " "
23
20
  NEXT_LINE_PROLOGUE = "\n" + LINE_INDENT
21
+ WHERE_PROLOGUE = NEXT_LINE_PROLOGUE[:-2] + WHERE_SEPARATOR + " "
22
+
23
+ TIME_PLACEHOLDER = TIME_LENGTH * ELAPSED_TIME_SEPARATOR
24
24
 
25
25
  expected_op_h = h.Literal[":", ": ", "=", "!=", ">=", "<="]
26
26
  EXPECTED_OP: tuple[str, ...] = h.get_args(expected_op_h)
@@ -4,6 +4,8 @@ Contributor(s): Eric Debreuve (eric.debreuve@cnrs.fr) since 2023
4
4
  SEE COPYRIGHT NOTICE BELOW
5
5
  """
6
6
 
7
+ HAS_ACTUAL_EXPECTED_ATTR = "has_actual_expected"
8
+ SHOW_WHEN_ATTR = "should_show_when"
7
9
  SHOW_WHERE_ATTR = "should_show_where"
8
10
  SHOW_W_RULE_ATTR = "should_show_w_rule"
9
11
  WHEN_OR_ELAPSED_ATTR = "when_or_elapsed"
@@ -4,14 +4,23 @@ Contributor(s): Eric Debreuve (eric.debreuve@cnrs.fr) since 2023
4
4
  SEE COPYRIGHT NOTICE BELOW
5
5
  """
6
6
 
7
- from logger_36.instance.logger import L
8
- from logger_36.task.measure.chronos import ElapsedTime
9
- from logger_36.type.logger import logger_t
7
+ import os as o
8
+ import tempfile as tmps
9
+ from pathlib import Path as path_t
10
10
 
11
11
 
12
- def LogElapsedTime(*, logger: logger_t = L) -> None:
12
+ def NewTemporaryFile(
13
+ suffix: str, /, *, should_return_accessor: bool = False
14
+ ) -> path_t | tuple[path_t, int]:
13
15
  """"""
14
- logger.info(f"Elapsed Time: {ElapsedTime()}")
16
+ accessor, path = tmps.mkstemp(suffix=suffix)
17
+ path = path_t(path)
18
+
19
+ if should_return_accessor:
20
+ return path, accessor
21
+
22
+ o.close(accessor)
23
+ return path
15
24
 
16
25
 
17
26
  """
@@ -11,9 +11,7 @@ def WrappedLines(lines: list[str], message_width: int, /) -> list[str]:
11
11
 
12
12
  for line in lines:
13
13
  while line.__len__() > message_width:
14
- if all(
15
- _elm != " " for _elm in line[(message_width - 1) : (message_width + 1)]
16
- ):
14
+ if all(_ != " " for _ in line[(message_width - 1) : (message_width + 1)]):
17
15
  if line[message_width - 2] == " ":
18
16
  piece, line = (
19
17
  line[: (message_width - 2)].rstrip(),
@@ -39,7 +39,7 @@ def FormattedUsage(
39
39
  raise ValueError(
40
40
  MessageWithActualExpected(
41
41
  "Invalid unit", actual=unit, expected=str(STORAGE_UNITS)[1:-1]
42
- )
42
+ )[0]
43
43
  )
44
44
 
45
45
  return value, unit