From 65efe8f0a63bfe273ec8cdb7489c853cc75d85aa Mon Sep 17 00:00:00 2001 From: DEBREUVE Eric <eric.debreuve@cnrs.fr> Date: Thu, 19 Sep 2024 15:21:49 +0200 Subject: [PATCH] logger now stores event counts, added DisplayRule, rich console interprets markup --- .../logger_36/catalog/handler/console_rich.py | 9 +++-- package/logger_36/task/format/message.py | 11 +---- package/logger_36/task/format/rule.py | 14 +++++-- package/logger_36/type/logger.py | 40 +++++++++++++------ package/logger_36/version.py | 2 +- test/main.py | 2 + 6 files changed, 47 insertions(+), 31 deletions(-) diff --git a/package/logger_36/catalog/handler/console_rich.py b/package/logger_36/catalog/handler/console_rich.py index 6d2aa5e..1091e6e 100644 --- a/package/logger_36/catalog/handler/console_rich.py +++ b/package/logger_36/catalog/handler/console_rich.py @@ -31,7 +31,6 @@ from logger_36.task.format.rule import Rule from logger_36.type.handler import handler_extension_t from rich.console import Console as console_t from rich.console import RenderableType as renderable_t -from rich.markup import escape as EscapedForRich from rich.text import Text as text_t from rich.traceback import install as InstallTracebackHandler @@ -140,7 +139,7 @@ class console_rich_handler_t(lggg.Handler): if hasattr(record, SHOW_W_RULE_ATTR): richer = Rule(record.msg, DATE_TIME_COLOR) else: - first, next_s = self.FormattedLines(record, PreProcessed=EscapedForRich) + first, next_s = self.FormattedLines(record) should_highlight_back = self.alternating_lines == 1 if self.alternating_lines >= 0: self.alternating_lines = (self.alternating_lines + 1) % 2 @@ -173,7 +172,9 @@ def HighlightedVersion( background_is_light: bool = True, ) -> renderable_t: """""" - output = text_t(first_line) + # TODO: Is there a way to use html or something to enable message styling, + # regardless of the handler (would require styling conversion; html->rich here). + output = text_t.from_markup(first_line) # Used instead of _CONTEXT_LENGTH which might include \t, thus creating a # mismatch between character length and length when displayed in console. @@ -193,7 +194,7 @@ def HighlightedVersion( output.stylize(ELAPSED_TIME_COLOR, start=elapsed_time_separator) if next_lines is not None: - output.append(next_lines) + output.append(text_t.from_markup(next_lines)) _ = output.highlight_regex(ACTUAL_PATTERNS, style=ACTUAL_COLOR) _ = output.highlight_regex(EXPECTED_PATTERNS, style=EXPECTED_COLOR) diff --git a/package/logger_36/task/format/message.py b/package/logger_36/task/format/message.py index d9e1f00..cff6f75 100644 --- a/package/logger_36/task/format/message.py +++ b/package/logger_36/task/format/message.py @@ -15,7 +15,7 @@ from logger_36.config.message import ( MESSAGE_MARKER, ) from logger_36.constant.generic import NOT_PASSED -from logger_36.constant.message import EXPECTED_OP, expected_op_h +from logger_36.constant.message import expected_op_h def MessageFormat(with_where: bool, with_memory_usage: bool, /) -> str: @@ -46,15 +46,6 @@ def FormattedMessage( with_final_dot: bool = True, ) -> str: """""" - if expected_op not in EXPECTED_OP: - raise ValueError( - FormattedMessage( - 'Invalid "expected" section operator', - actual=expected_op, - expected=f"One of {str(EXPECTED_OP)[1:-1]}", - ) - ) - if actual is NOT_PASSED: if with_final_dot: if message[-1] != ".": diff --git a/package/logger_36/task/format/rule.py b/package/logger_36/task/format/rule.py index f64ced3..74c65ec 100644 --- a/package/logger_36/task/format/rule.py +++ b/package/logger_36/task/format/rule.py @@ -5,18 +5,24 @@ SEE COPYRIGHT NOTICE BELOW """ -def RuleAsText(text: str, /) -> str: +def RuleAsText(text: str | None, /) -> str: """""" - return f"---- ---- ---- ---- {text} ---- ---- ---- ----" + if text is None: + return "---- ---- ---- ---- ---- ---- ---- ---- ----" + else: + return f"---- ---- ---- ---- {text} ---- ---- ---- ----" try: from rich.rule import Rule as rule_t from rich.text import Text as text_t - def Rule(text: str, color: str, /) -> rule_t: + def Rule(text: str | None, color: str, /) -> rule_t | str: """""" - return rule_t(title=text_t(text, style=f"bold {color}"), style=color) + if text is None: + return rule_t(style=color) + else: + return rule_t(title=text_t(text, style=f"bold {color}"), style=color) except ModuleNotFoundError: Rule = lambda _txt, _: RuleAsText(_txt) diff --git a/package/logger_36/type/logger.py b/package/logger_36/type/logger.py index c100c24..246db01 100644 --- a/package/logger_36/type/logger.py +++ b/package/logger_36/type/logger.py @@ -32,6 +32,7 @@ from logger_36.task.format.memory import ( FormattedUsageWithAutoUnit as FormattedMemoryUsage, ) from logger_36.task.format.message import FormattedMessage +from logger_36.task.format.rule import Rule from logger_36.task.measure.chronos import ElapsedTime from logger_36.task.measure.memory import CurrentUsage as CurrentMemoryUsage from logger_36.type.issue import NewIssue, issue_t @@ -42,12 +43,14 @@ class logger_t(lggg.Logger): name_: d.InitVar[str] = LOGGER_NAME level_: d.InitVar[int] = lggg.NOTSET activate_wrn_interceptions: d.InitVar[bool] = True - exit_on_error: bool = False # Implies exit_on_critical. - exit_on_critical: bool = False + # Must not be False until at least one handler has been added. should_hold_messages: bool = True + exit_on_error: bool = False # Implies exit_on_critical. + exit_on_critical: bool = False on_hold: list[lggg.LogRecord] = d.field(init=False, default_factory=list) + events: dict[int, int] = d.field(init=False, default_factory=dict) last_message_date: str = d.field(init=False, default="") any_handler_shows_memory: bool = d.field(init=False, default=False) memory_usages: list[tuple[str, int]] = d.field(init=False, default_factory=list) @@ -66,11 +69,19 @@ class logger_t(lggg.Logger): self.setLevel(level_) self.propagate = False # Part of lggg.Logger. + for level in lggg.getLevelNamesMapping().values(): + self.events[level] = 0 + if activate_wrn_interceptions: self._ActivateWarningInterceptions() if self.exit_on_error: self.exit_on_critical = True + def ResetEventCounts(self) -> None: + """""" + for level in self.events: + self.events[level] = 0 + def _ActivateWarningInterceptions(self) -> None: """ The log message will not appear if called from __post_init__ since there are no @@ -214,6 +225,7 @@ class logger_t(lggg.Logger): else: lggg.Logger.handle(self, record) + self.events[record.levelno] += 1 if (self.exit_on_critical and (record.levelno is lggg.CRITICAL)) or ( self.exit_on_error and (record.levelno is lggg.ERROR) ): @@ -264,6 +276,20 @@ class logger_t(lggg.Logger): message = f"{type(exception).__name__}:\n{formatted}" self.log(level, message) + def ShowMessage(self, message: str, /) -> None: + """ + See documentation of + logger_36.catalog.handler.generic.generic_handler_t.ShowMessage. + """ + for handler in self.handlers: + ShowMessage = getattr(handler, "ShowMessage", None) + if ShowMessage is not None: + ShowMessage(message) + + def DisplayRule(self, /, *, text: str | None = None, color: str = "white") -> None: + """""" + self.ShowMessage(Rule(text, color)) + def AddContextLevel(self, new_level: str, /) -> None: """""" self.context_levels.append(new_level) @@ -360,16 +386,6 @@ class logger_t(lggg.Logger): self.log(int(level), issue, stacklevel=2) self.staged_issues.clear() - def ShowMessage(self, message: str, /) -> None: - """ - See documentation of - logger_36.catalog.handler.generic.generic_handler_t.ShowMessage. - """ - for handler in self.handlers: - ShowMessage = getattr(handler, "ShowMessage", None) - if ShowMessage is not None: - ShowMessage(message) - def __enter__(self) -> None: """""" pass diff --git a/package/logger_36/version.py b/package/logger_36/version.py index 7e32636..c4a3382 100644 --- a/package/logger_36/version.py +++ b/package/logger_36/version.py @@ -4,7 +4,7 @@ Contributor(s): Eric Debreuve (eric.debreuve@cnrs.fr) since 2023 SEE COPYRIGHT NOTICE BELOW """ -__version__ = "2024.23" +__version__ = "2024.24" """ COPYRIGHT NOTICE diff --git a/test/main.py b/test/main.py index 96d8c2f..98d7636 100644 --- a/test/main.py +++ b/test/main.py @@ -61,6 +61,8 @@ with TemporaryDirectory() as tmp_folder: LogSystemDetails() + LOGGER.DisplayRule() + for level in ("debug", "info", "warning", "error", "critical"): LogMessage = getattr(LOGGER, level) LogMessage(f"{level.capitalize()} message") -- GitLab