Source code for id_translation.logging

"""Logging utilities; see :doc:`/documentation/translation-logging` for help."""

import logging as _l
import typing as _t
from random import Random as _Random
from time import perf_counter as _perf_counter

from rics.env import read as _env

ENABLE_VERBOSE_LOGGING: bool = _env.read_bool("ID_TRANSLATION_VERBOSE")
"""Set to enable additional ``DEBUG``-level messages.

The default (``False``) is controlled by the :envvar:`ID_TRANSLATION_VERBOSE` variable. Use
:func:`enable_verbose_debug_messages` to enable temporarily.
"""

LOGGER = _l.getLogger("id_translation")
"""Namespace root logger.

Level is set to ``logging.WARNING=30`` by default (or ``DEBUG`` if ``ENABLE_VERBOSE_LOGGING`` is set).
See :doc:`/documentation/translation-logging` for details.
"""
if LOGGER.level == _l.NOTSET:
    LOGGER.setLevel(_l.DEBUG if ENABLE_VERBOSE_LOGGING else _l.WARNING)


[docs] def enable_verbose_debug_messages( level: _t.Literal["verbose", "debug", "info", "warning"] = "verbose", *, use_custom_handler: bool | _t.Literal["auto"] = "auto", style: _t.Literal["minimal", "basic", "pretty", "rainbow"] = "pretty", ) -> _t.ContextManager[None]: """Enable verbose logging. May be used as a context. .. hint:: Click `here <../_static/logging-style-rainbow.html>`__ for sample output using ``style="rainbow"``. **Styles** * **minimal**: Nothing but the logged message itself. * **basic**: Adds logger name and level. * **pretty**: Adds basic color and task ID (e.g. ``🍏 0x2b92``). Mark stage (``enter=🚀, exit=✅``). * **rainbow**: Indent based on stage. Full-color syntax highlighting for strings and keywords. Args: level: Log level. If `'verbose'` (default), set :attr:`ENABLE_VERBOSE_LOGGING` to ``True``. use_custom_handler: Set to ``False`` to use existing handlers. If `'auto'` (default), use existing handlers if one is found (see :py:meth:`logging.Logger.hasHandlers`). If ``True``, propagation is disabled for the :data:`namespace root logger <LOGGER>`. style: Formatting style to use. Ignored when `use_custom_handler` evaluates to ``False``. Examples: Basic usage. >>> from id_translation.mapping import Mapper >>> with enable_verbose_debug_messages(): ... # Context manager; changes are temporary. ... Mapper().apply("ab", candidates="abc") Forcing custom handlers. These add formatting (e.g. color) to namespace logger messages. >>> enable_verbose_debug_messages(use_custom_handler=True, style="rainbow") >>> Mapper().apply("ab", candidates="abc") The changes aren't automatically undone if a regular function call is used. Notes: Custom handlers emit to standard out. """ global ENABLE_VERBOSE_LOGGING # noqa: PLW0603 if level.lower() == "verbose": level = "debug" verbose = True else: verbose = False verbose_before = ENABLE_VERBOSE_LOGGING level_before = LOGGER.level propagate_before = LOGGER.propagate LOGGER.setLevel(_l._nameToLevel[level.upper()]) ENABLE_VERBOSE_LOGGING = verbose if use_custom_handler == "auto" and not LOGGER.hasHandlers(): use_custom_handler = True handler: _l.Handler | None = None if use_custom_handler is True: from sys import stdout # noqa: PLC0415 if style == "minimal": formatter = _l.Formatter("%(message)s") elif style == "basic": formatter = _l.Formatter("[%(name)s:%(levelname)s] %(message)s") else: from ._utils.debug_logging_formatter import DebugLoggingFormatter # noqa: PLC0415 formatter = DebugLoggingFormatter(less=style == "pretty", indent_style=".." if verbose else "") handler = _l.StreamHandler(stdout) handler.setFormatter(formatter) LOGGER.addHandler(handler) LOGGER.propagate = False # Prevent duplicate output. def undo() -> None: """Restore original state.""" global ENABLE_VERBOSE_LOGGING # noqa: PLW0603 LOGGER.setLevel(level_before) ENABLE_VERBOSE_LOGGING = verbose_before if handler: LOGGER.propagate = propagate_before LOGGER.removeHandler(handler) class Undo(_t.ContextManager[None]): def __exit__(self, *_: _t.Any) -> None: undo() return Undo()
[docs] def generate_task_id(seed: float | None = None) -> int: """Generate a new task ID.""" if seed is None: seed = _perf_counter() random = _Random(seed) # noqa: S311 return random.randint(0, 65535) # 65535 = 0xFFFF
[docs] def get_event_key(method: _t.Any, stage: str) -> str: """Construct `event_key` value.""" cls = type(method.__self__).__name__ return f"{cls}.{method.__name__}:{stage}"