Source code for robot.output.loggerhelper

#  Copyright 2008-2015 Nokia Networks
#  Copyright 2016-     Robot Framework Foundation
#
#  Licensed under the Apache License, Version 2.0 (the "License");
#  you may not use this file except in compliance with the License.
#  You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
#  Unless required by applicable law or agreed to in writing, software
#  distributed under the License is distributed on an "AS IS" BASIS,
#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#  See the License for the specific language governing permissions and
#  limitations under the License.

import sys
from datetime import datetime
from typing import Callable, Literal

from robot.errors import DataError
from robot.model import MessageLevel
from robot.result import Message as BaseMessage
from robot.utils import console_encode

from .loglevel import LEVELS

PseudoLevel = Literal["HTML", "CONSOLE"]


[docs] def write_to_console(msg, newline=True, stream="stdout"): msg = str(msg) if newline: msg += "\n" stream = sys.__stdout__ if stream.lower() != "stderr" else sys.__stderr__ if stream: stream.write(console_encode(msg, stream=stream)) stream.flush()
[docs] class AbstractLogger:
[docs] def trace(self, msg): self.write(msg, "TRACE")
[docs] def debug(self, msg): self.write(msg, "DEBUG")
[docs] def info(self, msg): self.write(msg, "INFO")
[docs] def warn(self, msg): self.write(msg, "WARN")
[docs] def fail(self, msg): html = False if msg.startswith("*HTML*"): html = True msg = msg[6:].lstrip() self.write(msg, "FAIL", html)
[docs] def skip(self, msg): html = False if msg.startswith("*HTML*"): html = True msg = msg[6:].lstrip() self.write(msg, "SKIP", html)
[docs] def error(self, msg): self.write(msg, "ERROR")
[docs] def write(self, message, level, html=False): self.message(Message(message, level, html))
[docs] def message(self, msg): raise NotImplementedError(self.__class__)
[docs] class Message(BaseMessage): """Represents message logged during execution. Most messages are logged by libraries. They typically log strings, but possible non-string items have been converted to strings already before they end up here. In addition to strings, Robot Framework itself logs also callables to make constructing messages that are not typically needed lazy. Such messages are resolved when they are accessed. Listeners can remove messages by setting the `message` attribute to `None`. These messages are not written to the output.xml at all. """ __slots__ = ("_message",) def __init__( self, message: "str|None|Callable[[], str|None]" = "", level: "MessageLevel|PseudoLevel" = "INFO", html: bool = False, timestamp: "datetime|str|None" = None, ): level, html = self._get_level_and_html(level, html) super().__init__(message, level, html, timestamp or datetime.now()) def _get_level_and_html(self, level, html) -> "tuple[MessageLevel, bool]": level = level.upper() if level == "HTML": return "INFO", True if level == "CONSOLE": return "INFO", html if level in LEVELS: return level, html raise DataError(f"Invalid log level '{level}'.") @property def message(self) -> "str|None": self.resolve_delayed_message() return self._message @message.setter def message(self, message: "str|None|Callable[[], str|None]"): if isinstance(message, str) and "\r\n" in message: message = message.replace("\r\n", "\n") self._message = message
[docs] def resolve_delayed_message(self): if callable(self._message): self.message = self._message()