logger-36 2025.23__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.
Files changed (40) hide show
  1. logger_36/api/{gpu.py → chronos.py} +1 -1
  2. logger_36/api/memory.py +0 -9
  3. logger_36/api/storage.py +0 -1
  4. logger_36/catalog/handler/console.py +1 -1
  5. logger_36/catalog/handler/console_rich.py +33 -22
  6. logger_36/catalog/handler/file.py +1 -2
  7. logger_36/catalog/handler/generic.py +24 -10
  8. logger_36/catalog/handler/memory.py +31 -6
  9. logger_36/catalog/logger/chronos.py +10 -2
  10. logger_36/catalog/logger/memory.py +1 -1
  11. logger_36/catalog/logger/system.py +6 -5
  12. logger_36/config/message.py +1 -4
  13. logger_36/{api/system.py → config/rule.py} +2 -1
  14. logger_36/constant/chronos.py +50 -0
  15. logger_36/constant/error.py +2 -0
  16. logger_36/constant/html.py +2 -0
  17. logger_36/constant/message.py +7 -7
  18. logger_36/constant/path.py +8 -7
  19. logger_36/constant/record.py +2 -0
  20. logger_36/constant/rule.py +2 -2
  21. logger_36/{api/time.py → extension/file.py} +18 -2
  22. logger_36/{task → extension}/inspection.py +15 -29
  23. logger_36/extension/line.py +1 -1
  24. logger_36/task/format/memory.py +1 -1
  25. logger_36/task/format/message.py +7 -5
  26. logger_36/task/measure/chronos.py +21 -13
  27. logger_36/task/storage.py +32 -48
  28. logger_36/type/handler.py +26 -32
  29. logger_36/type/issue.py +7 -4
  30. logger_36/type/logger.py +164 -88
  31. logger_36/version.py +1 -1
  32. {logger_36-2025.23.dist-info → logger_36-2025.25.dist-info}/METADATA +30 -44
  33. logger_36-2025.25.dist-info/RECORD +53 -0
  34. logger_36/extension/html_.py +0 -93
  35. logger_36-2025.23.dist-info/RECORD +0 -53
  36. /logger_36/api/{type.py → logger.py} +0 -0
  37. /logger_36/api/{content.py → message.py} +0 -0
  38. /logger_36/{constant/generic.py → extension/sentinel.py} +0 -0
  39. {logger_36-2025.23.dist-info → logger_36-2025.25.dist-info}/WHEEL +0 -0
  40. {logger_36-2025.23.dist-info → logger_36-2025.25.dist-info}/top_level.txt +0 -0
@@ -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.catalog.logger.gpu import LogGPURelatedDetails # noqa
7
+ from logger_36.task.measure.chronos import FormattedElapsedTime, TimeStamp # noqa
8
8
 
9
9
  """
10
10
  COPYRIGHT NOTICE
logger_36/api/memory.py CHANGED
@@ -4,15 +4,6 @@ Contributor(s): Eric Debreuve (eric.debreuve@cnrs.fr) since 2023
4
4
  SEE COPYRIGHT NOTICE BELOW
5
5
  """
6
6
 
7
- from logger_36.catalog.logger.memory import ( # noqa
8
- LogMaximumMemoryUsage,
9
- LogMemoryUsages,
10
- )
11
- from logger_36.task.format.memory import FormattedUsage as FormattedMemoryUsage # noqa
12
- from logger_36.task.format.memory import ( # noqa
13
- FormattedUsageWithAutoUnit as FormattedMemoryUsageWithAutoUnit,
14
- )
15
- from logger_36.task.format.memory import UsageBar as MemoryUsageBar # noqa
16
7
  from logger_36.task.measure.memory import CanCheckUsage as CanCheckMemoryUsage # noqa
17
8
  from logger_36.task.measure.memory import CurrentUsage as CurrentMemoryUsage # noqa
18
9
 
logger_36/api/storage.py CHANGED
@@ -4,7 +4,6 @@ Contributor(s): Eric Debreuve (eric.debreuve@cnrs.fr) since 2023
4
4
  SEE COPYRIGHT NOTICE BELOW
5
5
  """
6
6
 
7
- from logger_36.extension.html_ import html_content_t # noqa
8
7
  from logger_36.task.storage import SaveLOGasHTML # noqa
9
8
 
10
9
  """
@@ -8,7 +8,7 @@ import logging as l
8
8
  import sys as s
9
9
  import typing as h
10
10
 
11
- from logger_36.type.handler import handler_t as base_t
11
+ from logger_36.type.handler import non_file_handler_t as base_t
12
12
 
13
13
 
14
14
  class console_handler_t(base_t):
@@ -11,6 +11,7 @@ from rich.console import Console as console_t # noqa
11
11
  from rich.console import RenderableType as renderable_t # noqa
12
12
  from rich.markup import escape as EscapedVersion # noqa
13
13
  from rich.rule import Rule as rule_t # noqa
14
+ from rich.style import Style as style_t # noqa
14
15
  from rich.text import Text as text_t # noqa
15
16
  from rich.traceback import install as InstallTracebackHandler # noqa
16
17
 
@@ -24,9 +25,10 @@ from logger_36.catalog.config.console_rich import (
24
25
  RULE_COLOR,
25
26
  WHITE_COLOR,
26
27
  )
27
- from logger_36.config.message import ACTUAL_PATTERNS, EXPECTED_PATTERNS, WHERE_SEPARATOR
28
+ from logger_36.config.message import ACTUAL_PATTERNS, EXPECTED_PATTERNS
28
29
  from logger_36.constant.message import CONTEXT_LENGTH
29
- from logger_36.type.handler import handler_t as base_t
30
+ from logger_36.constant.record import HAS_ACTUAL_EXPECTED_ATTR
31
+ from logger_36.type.handler import non_file_handler_t as base_t
30
32
 
31
33
  _COMMON_TRACEBACK_ARGUMENTS = ("theme", "width")
32
34
  _EXCLUSIVE_TRACEBACK_ARGUMENTS = (
@@ -62,8 +64,13 @@ class console_rich_handler_t(base_t):
62
64
  base_t.__init__(self, name, message_width, EscapedVersion, level, kwargs)
63
65
 
64
66
  self.console = None # console_t | None.
65
- self.alternating_logs = alternating_logs
66
- self._log_parity = False
67
+ if alternating_logs == 0:
68
+ self.background_style = None
69
+ elif alternating_logs == 1:
70
+ self.background_style = ALTERNATIVE_BACKGROUND_FOR_DARK
71
+ else:
72
+ self.background_style = ALTERNATIVE_BACKGROUND_FOR_LIGHT
73
+ self._should_style_background = False
67
74
 
68
75
  self.__post_init_local__(should_install_traceback, **kwargs)
69
76
 
@@ -104,17 +111,24 @@ class console_rich_handler_t(base_t):
104
111
 
105
112
  def emit(self, record: l.LogRecord, /) -> None:
106
113
  """"""
107
- message, is_not_a_rule = self.MessageFromRecord(record, rule_color=RULE_COLOR)
114
+ message, is_not_a_rule, where_location = self.MessageFromRecord(
115
+ record, rule_color=RULE_COLOR
116
+ )
108
117
  if is_not_a_rule:
118
+ if self._should_style_background:
119
+ background_style = self.background_style
120
+ else:
121
+ background_style = None
109
122
  message = HighlightedVersion(
110
123
  self.console,
111
124
  message,
125
+ getattr(record, HAS_ACTUAL_EXPECTED_ATTR, False),
126
+ where_location,
112
127
  record.levelno,
113
- self.alternating_logs,
114
- self._log_parity,
128
+ background_style,
115
129
  )
116
130
  self.console.print(message, crop=False, overflow="ignore")
117
- self._log_parity = not self._log_parity
131
+ self._should_style_background = not self._should_style_background
118
132
 
119
133
  def EmitMessage(self, message: str | renderable_t, /) -> None:
120
134
  """"""
@@ -124,27 +138,24 @@ class console_rich_handler_t(base_t):
124
138
  def HighlightedVersion(
125
139
  _: console_t,
126
140
  message: str,
141
+ has_actual_expected: bool,
142
+ where_location: int | None,
127
143
  log_level: int,
128
- alternating_logs: int,
129
- should_tint_background: bool,
144
+ background_style: style_t | None,
130
145
  /,
131
146
  ) -> renderable_t:
132
147
  """"""
133
148
  output = text_t(message, WHITE_COLOR)
134
149
 
135
150
  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)
151
+ if where_location is not None:
152
+ output.stylize(GRAY_COLOR, start=where_location)
153
+ if has_actual_expected:
154
+ _ = output.highlight_words(ACTUAL_PATTERNS, style=ACTUAL_COLOR)
155
+ _ = output.highlight_regex(EXPECTED_PATTERNS, style=EXPECTED_COLOR)
156
+
157
+ if background_style is not None:
158
+ output.stylize(background_style)
148
159
 
149
160
  return output
150
161
 
@@ -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,22 +8,26 @@ 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
24
28
  ) = HighlightedVersion = None
25
29
 
26
- from logger_36.type.handler import handler_t as base_t
30
+ from logger_36.type.handler import non_file_handler_t as base_t
27
31
 
28
32
 
29
33
  class generic_handler_t(base_t):
@@ -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
 
@@ -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
  """
@@ -8,9 +8,13 @@ import json
8
8
  import logging as l
9
9
  import typing as h
10
10
 
11
- from logger_36.type.handler import handler_t as base_t
11
+ from logger_36.type.handler import non_file_handler_t as base_t
12
12
 
13
- formats_h = h.Literal["json", "message", "raw"]
13
+ formats_h = h.Literal["dict", "json", "message", "raw"]
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]
14
18
 
15
19
 
16
20
  class memory_handler_t(base_t):
@@ -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(
@@ -45,11 +49,14 @@ class memory_handler_t(base_t):
45
49
 
46
50
  if self.format_ == "raw":
47
51
  is_not_a_rule = True
48
- elif self.format_ == "message":
49
- record, is_not_a_rule = self.MessageFromRecord(record)
50
- else:
52
+ elif self.format_ == "dict":
53
+ record = dict(record.__dict__)
54
+ is_not_a_rule = True
55
+ elif self.format_ == "json":
51
56
  record = json.dumps(record.__dict__)
52
57
  is_not_a_rule = True
58
+ else:
59
+ record, is_not_a_rule, _ = self.MessageFromRecord(record)
53
60
 
54
61
  self.records.append((level, record, is_not_a_rule))
55
62
 
@@ -64,6 +71,24 @@ class memory_handler_t(base_t):
64
71
  )
65
72
  self.emit(record)
66
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
+
67
92
 
68
93
  """
69
94
  COPYRIGHT NOTICE
@@ -4,14 +4,22 @@ Contributor(s): Eric Debreuve (eric.debreuve@cnrs.fr) since 2023
4
4
  SEE COPYRIGHT NOTICE BELOW
5
5
  """
6
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
7
11
  from logger_36.instance.logger import L
8
- from logger_36.task.measure.chronos import ElapsedTime
12
+ from logger_36.task.measure.chronos import FormattedElapsedTime
9
13
  from logger_36.type.logger import logger_t
10
14
 
11
15
 
12
16
  def LogElapsedTime(*, logger: logger_t = L) -> None:
13
17
  """"""
14
- logger.info(f"Elapsed Time: {ElapsedTime()}")
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
+ )
15
23
 
16
24
 
17
25
  """
@@ -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)
@@ -5,16 +5,17 @@ SEE COPYRIGHT NOTICE BELOW
5
5
  """
6
6
 
7
7
  from logger_36.constant.system import MAX_DETAIL_NAME_LENGTH, SYSTEM_DETAILS_AS_DICT
8
+ from logger_36.extension.inspection import Modules
8
9
  from logger_36.instance.logger import L
9
- from logger_36.task.inspection import Modules
10
10
  from logger_36.type.logger import logger_t
11
11
 
12
12
 
13
13
  def LogSystemDetails(
14
14
  *,
15
+ should_restrict_modules_to_loaded: bool = True,
15
16
  modules_with_version: bool = True,
16
17
  modules_formatted: bool = True,
17
- should_restrict_modules_to_loaded: bool = True,
18
+ indent: int = 4,
18
19
  logger: logger_t = L,
19
20
  ) -> None:
20
21
  """"""
@@ -23,10 +24,10 @@ def LogSystemDetails(
23
24
  for _key, _vle in SYSTEM_DETAILS_AS_DICT.items()
24
25
  )
25
26
  modules = Modules(
26
- modules_with_version,
27
- modules_formatted,
28
27
  only_loaded=should_restrict_modules_to_loaded,
29
- indent=4,
28
+ with_version=modules_with_version,
29
+ formatted=modules_formatted,
30
+ indent=indent,
30
31
  )
31
32
 
32
33
  logger.info(
@@ -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"
@@ -4,7 +4,8 @@ Contributor(s): Eric Debreuve (eric.debreuve@cnrs.fr) since 2023
4
4
  SEE COPYRIGHT NOTICE BELOW
5
5
  """
6
6
 
7
- from logger_36.catalog.logger.system import LogSystemDetails # noqa
7
+ RULE_CHARACTER = "-"
8
+ DEFAULT_RULE_LENGTH = 50
8
9
 
9
10
  """
10
11
  COPYRIGHT NOTICE
@@ -0,0 +1,50 @@
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.config.message import DATE_FORMAT, TIME_FORMAT
10
+
11
+ # This module is imported early. Therefore, the current date and time should be close
12
+ # enough to the real start date and time of the main script.
13
+ START_DATE_TIME = date_time_t.now()
14
+
15
+ FORMATTED_START_DATE_TIME = f"{START_DATE_TIME:{TIME_FORMAT + ' on ' + DATE_FORMAT}}"
16
+
17
+ DATE_TIME_ORIGIN = date_time_t.fromtimestamp(1970, None)
18
+ DATE_ORIGIN = DATE_TIME_ORIGIN.date()
19
+
20
+ """
21
+ COPYRIGHT NOTICE
22
+
23
+ This software is governed by the CeCILL license under French law and
24
+ abiding by the rules of distribution of free software. You can use,
25
+ modify and/ or redistribute the software under the terms of the CeCILL
26
+ license as circulated by CEA, CNRS and INRIA at the following URL
27
+ "http://www.cecill.info".
28
+
29
+ As a counterpart to the access to the source code and rights to copy,
30
+ modify and redistribute granted by the license, users are provided only
31
+ with a limited warranty and the software's author, the holder of the
32
+ economic rights, and the successive licensors have only limited
33
+ liability.
34
+
35
+ In this respect, the user's attention is drawn to the risks associated
36
+ with loading, using, modifying and/or developing or reproducing the
37
+ software by the user in light of its specific status of free software,
38
+ that may mean that it is complicated to manipulate, and that also
39
+ therefore means that it is reserved for developers and experienced
40
+ professionals having in-depth computer knowledge. Users are therefore
41
+ encouraged to load and test the software's suitability as regards their
42
+ requirements in conditions enabling the security of their systems and/or
43
+ data to be ensured and, more generally, to use and operate it in the
44
+ same conditions as regards security.
45
+
46
+ The fact that you are presently reading this means that you have had
47
+ knowledge of the CeCILL license and that you accept its terms.
48
+
49
+ SEE LICENCE NOTICE: file README-LICENCE-utf8.txt at project source root.
50
+ """
@@ -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)
@@ -12,15 +12,16 @@ USER_FOLDER = path_t.home()
12
12
 
13
13
  frame = e.stack(context=0)[-1] # -1=root caller.
14
14
  if path_t(frame.filename).exists():
15
- PROJECT_FILE = path_t(frame.filename)
16
- if PROJECT_FILE.is_relative_to(USER_FOLDER):
17
- PROJECT_FILE_RELATIVE = PROJECT_FILE.relative_to(USER_FOLDER)
15
+ LAUNCH_ROOT_FILE = path_t(frame.filename)
16
+ LAUNCH_FOLDER = LAUNCH_ROOT_FILE.parent
17
+
18
+ if LAUNCH_ROOT_FILE.is_relative_to(USER_FOLDER):
19
+ LAUNCH_ROOT_FILE_relative = LAUNCH_ROOT_FILE.relative_to(USER_FOLDER)
18
20
  else:
19
- PROJECT_FILE_RELATIVE = PROJECT_FILE
20
- PROJECT_FOLDER = PROJECT_FILE.parent
21
+ LAUNCH_ROOT_FILE_relative = LAUNCH_ROOT_FILE
21
22
  else:
22
- PROJECT_FILE = PROJECT_FILE_RELATIVE = "<unknown>"
23
- PROJECT_FOLDER = path_t(tmps.mkdtemp())
23
+ LAUNCH_ROOT_FILE = LAUNCH_ROOT_FILE_relative = "<unknown launch root file>"
24
+ LAUNCH_FOLDER = path_t(tmps.mkdtemp())
24
25
 
25
26
  """
26
27
  COPYRIGHT NOTICE
@@ -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,9 +4,9 @@ Contributor(s): Eric Debreuve (eric.debreuve@cnrs.fr) since 2023
4
4
  SEE COPYRIGHT NOTICE BELOW
5
5
  """
6
6
 
7
- RULE_CHARACTER = "-"
7
+ from logger_36.config.rule import DEFAULT_RULE_LENGTH, RULE_CHARACTER
8
+
8
9
  MIN_HALF_RULE_LENGTH = 4
9
- DEFAULT_RULE_LENGTH = 50
10
10
  DEFAULT_RULE = DEFAULT_RULE_LENGTH * RULE_CHARACTER
11
11
 
12
12
  """
@@ -4,8 +4,24 @@ Contributor(s): Eric Debreuve (eric.debreuve@cnrs.fr) since 2023
4
4
  SEE COPYRIGHT NOTICE BELOW
5
5
  """
6
6
 
7
- from logger_36.catalog.logger.chronos import LogElapsedTime # noqa
8
- from logger_36.task.measure.chronos import ElapsedTime, TimeStamp # noqa
7
+ import os as o
8
+ import tempfile as tmps
9
+ from pathlib import Path as path_t
10
+
11
+
12
+ def NewTemporaryFile(
13
+ suffix: str, /, *, should_return_accessor: bool = False
14
+ ) -> path_t | tuple[path_t, int]:
15
+ """"""
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
24
+
9
25
 
10
26
  """
11
27
  COPYRIGHT NOTICE
@@ -4,14 +4,16 @@ Contributor(s): Eric Debreuve (eric.debreuve@cnrs.fr) since 2023
4
4
  SEE COPYRIGHT NOTICE BELOW
5
5
  """
6
6
 
7
- import importlib.metadata as mprt
8
7
  import pkgutil as pkgs
9
8
  import sys as s
10
- from types import FunctionType, MethodType
11
9
 
12
10
 
13
11
  def Modules(
14
- with_version: bool, formatted: bool, /, *, only_loaded: bool = True, indent: int = 0
12
+ *,
13
+ only_loaded: bool = True,
14
+ with_version: bool = True,
15
+ formatted: bool = False,
16
+ indent: int = 0,
15
17
  ) -> tuple[str, ...] | str:
16
18
  """"""
17
19
  output = []
@@ -61,23 +63,6 @@ def Modules(
61
63
  return tuple(output)
62
64
 
63
65
 
64
- def WhereFunction(function: FunctionType, /) -> str:
65
- """"""
66
- return f"{function.__module__}:{function.__name__}"
67
-
68
-
69
- def WhereMethod(instance: object, method: MethodType, /) -> str:
70
- """
71
- method: Could be a str instead, which would require changing method.__name__ into
72
- getattr(cls, method). But if the method name changes while forgetting to change the
73
- string in the call to WhereMethod accordingly, then an exception would be raised
74
- here.
75
- """
76
- cls = instance.__class__
77
-
78
- return f"{cls.__module__}:{cls.__name__}:{method.__name__}"
79
-
80
-
81
66
  def _ModulesUsingPkgUtil() -> tuple[str, ...]:
82
67
  """
83
68
  Returns more results than using importlib.
@@ -91,15 +76,16 @@ def _ModulesUsingPkgUtil() -> tuple[str, ...]:
91
76
  )
92
77
 
93
78
 
94
- def _ModulesUsingImportlib() -> tuple[str, ...]:
95
- """"""
96
- return tuple(
97
- sorted(
98
- _elm
99
- for _elm in mprt.packages_distributions()
100
- if (_elm[0] != "_") and ("__" not in _elm) and ("/" not in _elm)
101
- )
102
- )
79
+ # import importlib.metadata as mprt
80
+ # def _ModulesUsingImportlib() -> tuple[str, ...]:
81
+ # """"""
82
+ # return tuple(
83
+ # sorted(
84
+ # _elm
85
+ # for _elm in mprt.packages_distributions()
86
+ # if (_elm[0] != "_") and ("__" not in _elm) and ("/" not in _elm)
87
+ # )
88
+ # )
103
89
 
104
90
 
105
91
  """
@@ -12,7 +12,7 @@ def WrappedLines(lines: list[str], message_width: int, /) -> list[str]:
12
12
  for line in lines:
13
13
  while line.__len__() > message_width:
14
14
  if all(
15
- _elm != " " for _elm in line[(message_width - 1) : (message_width + 1)]
15
+ _ != " " for _ in line[(message_width - 1) : (message_width + 1)]
16
16
  ):
17
17
  if line[message_width - 2] == " ":
18
18
  piece, line = (
@@ -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