logger-36 2025.24__py3-none-any.whl → 2025.26__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/api/{time.py → chronos.py} +1 -1
- logger_36/catalog/handler/console_rich.py +39 -29
- logger_36/catalog/handler/file.py +1 -2
- logger_36/catalog/handler/generic.py +24 -10
- logger_36/catalog/handler/memory.py +24 -2
- logger_36/catalog/logger/chronos.py +10 -2
- logger_36/catalog/logger/memory.py +1 -1
- logger_36/config/message.py +1 -4
- logger_36/constant/{date_time.py → chronos.py} +4 -0
- logger_36/constant/error.py +2 -0
- logger_36/constant/html.py +2 -0
- logger_36/constant/message.py +7 -7
- logger_36/constant/record.py +2 -0
- logger_36/extension/{record.py → file.py} +11 -21
- logger_36/extension/line.py +1 -3
- logger_36/task/format/memory.py +1 -1
- logger_36/task/format/message.py +7 -5
- logger_36/task/measure/chronos.py +21 -11
- logger_36/task/storage.py +30 -55
- logger_36/type/handler.py +22 -24
- logger_36/type/issue.py +7 -4
- logger_36/type/logger.py +157 -51
- logger_36/type/loggers.py +0 -2
- logger_36/version.py +1 -1
- {logger_36-2025.24.dist-info → logger_36-2025.26.dist-info}/METADATA +30 -44
- logger_36-2025.26.dist-info/RECORD +53 -0
- logger_36-2025.24.dist-info/RECORD +0 -53
- /logger_36/{constant/generic.py → extension/sentinel.py} +0 -0
- {logger_36-2025.24.dist-info → logger_36-2025.26.dist-info}/WHEEL +0 -0
- {logger_36-2025.24.dist-info → logger_36-2025.26.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.task.measure.chronos import
|
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
|
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
|
-
|
66
|
-
|
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
|
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(
|
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
|
-
|
114
|
-
self._log_parity,
|
127
|
+
background_style,
|
115
128
|
)
|
116
129
|
self.console.print(message, crop=False, overflow="ignore")
|
117
|
-
self.
|
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
|
-
|
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
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
if
|
143
|
-
|
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
|
-
|
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
|
-
|
58
|
-
|
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
|
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
|
-
|
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.
|
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
|
@@ -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
|
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(
|
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
|
"""
|
logger_36/config/message.py
CHANGED
@@ -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 =
|
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
|
|
logger_36/constant/error.py
CHANGED
logger_36/constant/html.py
CHANGED
logger_36/constant/message.py
CHANGED
@@ -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
|
-
|
20
|
-
|
21
|
-
|
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)
|
logger_36/constant/record.py
CHANGED
@@ -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,33 +4,23 @@ Contributor(s): Eric Debreuve (eric.debreuve@cnrs.fr) since 2023
|
|
4
4
|
SEE COPYRIGHT NOTICE BELOW
|
5
5
|
"""
|
6
6
|
|
7
|
-
import
|
8
|
-
import
|
9
|
-
from os import sep as FOLDER_SEPARATOR
|
7
|
+
import os as o
|
8
|
+
import tempfile as tmps
|
10
9
|
from pathlib import Path as path_t
|
11
10
|
|
12
|
-
from logger_36.constant.path import USER_FOLDER
|
13
|
-
from logger_36.constant.record import WHERE_ATTR
|
14
11
|
|
15
|
-
|
16
|
-
|
12
|
+
def NewTemporaryFile(
|
13
|
+
suffix: str, /, *, should_return_accessor: bool = False
|
14
|
+
) -> path_t | tuple[path_t, int]:
|
17
15
|
""""""
|
18
|
-
|
19
|
-
|
20
|
-
if module.is_relative_to(path):
|
21
|
-
module = module.relative_to(path).with_suffix("")
|
22
|
-
module = str(module).replace(FOLDER_SEPARATOR, ".")
|
23
|
-
break
|
24
|
-
else:
|
25
|
-
if module.is_relative_to(USER_FOLDER):
|
26
|
-
module = module.relative_to(USER_FOLDER)
|
27
|
-
|
28
|
-
output = f"{module}:{record.funcName}:{record.lineno}"
|
16
|
+
accessor, path = tmps.mkstemp(suffix=suffix)
|
17
|
+
path = path_t(path)
|
29
18
|
|
30
|
-
if
|
31
|
-
|
19
|
+
if should_return_accessor:
|
20
|
+
return path, accessor
|
32
21
|
|
33
|
-
|
22
|
+
o.close(accessor)
|
23
|
+
return path
|
34
24
|
|
35
25
|
|
36
26
|
"""
|
logger_36/extension/line.py
CHANGED
@@ -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(),
|
logger_36/task/format/memory.py
CHANGED
logger_36/task/format/message.py
CHANGED
@@ -7,8 +7,8 @@ SEE COPYRIGHT NOTICE BELOW
|
|
7
7
|
import difflib as diff
|
8
8
|
import typing as h
|
9
9
|
|
10
|
-
from logger_36.constant.generic import NOT_PASSED
|
11
10
|
from logger_36.constant.message import expected_op_h
|
11
|
+
from logger_36.extension.sentinel import NOT_PASSED
|
12
12
|
|
13
13
|
|
14
14
|
def MessageWithActualExpected(
|
@@ -20,8 +20,10 @@ def MessageWithActualExpected(
|
|
20
20
|
expected_is_choices: bool = False,
|
21
21
|
expected_op: expected_op_h = "=",
|
22
22
|
with_final_dot: bool = True,
|
23
|
-
) -> str:
|
24
|
-
"""
|
23
|
+
) -> tuple[str, bool]:
|
24
|
+
"""
|
25
|
+
Second return: has_actual_expected.
|
26
|
+
"""
|
25
27
|
if actual is NOT_PASSED:
|
26
28
|
if with_final_dot:
|
27
29
|
if message[-1] != ".":
|
@@ -29,7 +31,7 @@ def MessageWithActualExpected(
|
|
29
31
|
elif message[-1] == ".":
|
30
32
|
message = message[:-1]
|
31
33
|
|
32
|
-
return message
|
34
|
+
return message, False
|
33
35
|
|
34
36
|
if message[-1] == ".":
|
35
37
|
message = message[:-1]
|
@@ -44,7 +46,7 @@ def MessageWithActualExpected(
|
|
44
46
|
else:
|
45
47
|
actual = f"{actual}:{type(actual).__name__}"
|
46
48
|
|
47
|
-
return f"{message}: Actual={actual}; {expected}{dot}"
|
49
|
+
return f"{message}: Actual={actual}; {expected}{dot}", True
|
48
50
|
|
49
51
|
|
50
52
|
def _FormattedExpected(
|
@@ -4,32 +4,42 @@ Contributor(s): Eric Debreuve (eric.debreuve@cnrs.fr) since 2023
|
|
4
4
|
SEE COPYRIGHT NOTICE BELOW
|
5
5
|
"""
|
6
6
|
|
7
|
-
import time
|
8
7
|
from datetime import datetime as date_time_t
|
9
8
|
|
10
|
-
from logger_36.
|
9
|
+
from logger_36.config.message import ELAPSED_TIME_SEPARATOR
|
10
|
+
from logger_36.constant.chronos import START_DATE_TIME
|
11
|
+
from logger_36.constant.message import TIME_LENGTH
|
11
12
|
|
12
13
|
|
13
14
|
def TimeStamp(*, precision: str = "microseconds") -> str:
|
14
|
-
"""
|
15
|
+
"""
|
16
|
+
precision: See documentation of date_time_t.isoformat.
|
17
|
+
"""
|
15
18
|
return (
|
16
19
|
date_time_t.now()
|
17
20
|
.isoformat(timespec=precision)
|
18
|
-
.replace(".", "
|
21
|
+
.replace(".", "_")
|
19
22
|
.replace(":", "-")
|
20
23
|
)
|
21
24
|
|
22
25
|
|
23
|
-
def
|
26
|
+
def FormattedElapsedTime(
|
27
|
+
now: date_time_t, /, *, reference: date_time_t = START_DATE_TIME
|
28
|
+
) -> str:
|
24
29
|
""""""
|
25
|
-
|
26
|
-
|
27
|
-
output
|
30
|
+
output = str(now - reference)
|
31
|
+
|
32
|
+
if output.startswith("0:"):
|
33
|
+
output = output[2:]
|
28
34
|
while output.startswith("00:"):
|
29
|
-
output = output
|
35
|
+
output = output[3:]
|
36
|
+
if output[0] == "0":
|
37
|
+
output = output[1:]
|
38
|
+
|
39
|
+
output = ELAPSED_TIME_SEPARATOR + output
|
30
40
|
|
31
|
-
if
|
32
|
-
return output
|
41
|
+
if output.__len__() > TIME_LENGTH:
|
42
|
+
return output[:TIME_LENGTH]
|
33
43
|
return output
|
34
44
|
|
35
45
|
|