Source code for mmm_framework.utils.log_errors
"""Observable error suppression.
The codebase has many ``try: ... except Exception: pass`` blocks that swallow
failures silently — the dangerous failure mode where a report section renders
empty or a tool no-ops while the caller (and the user) see a clean result with a
hole in it. This is the sanctioned replacement: suppress the exception (so the
best-effort path still degrades gracefully) but LOG it, so the failure is
observable instead of invisible.
Use it for genuinely-optional best-effort work::
from mmm_framework.utils.log_errors import logged_suppress
with logged_suppress("extracting saturation curves"):
bundle.saturation = self._extract_saturation()
For code that should NOT swallow (anything producing a business number), let the
exception propagate — do not reach for this.
"""
from __future__ import annotations
from contextlib import contextmanager
from loguru import logger
[docs]
@contextmanager
def logged_suppress(
context: str,
*exceptions: type[BaseException],
level: str = "DEBUG",
):
"""Suppress ``exceptions`` (default: ``Exception``) but log them with ``context``.
Parameters
----------
context : str
Short description of the optional work being attempted, included in the
log line so a swallowed failure can be traced.
*exceptions : exception types
Which exceptions to suppress. Defaults to ``Exception`` (not
``BaseException`` — KeyboardInterrupt/SystemExit always propagate).
level : str
loguru level for the log line (default ``DEBUG``).
"""
exc_types = exceptions or (Exception,)
try:
yield
except exc_types as e: # noqa: BLE001 - this is the sanctioned suppression point
logger.opt(exception=True).log(
level, "Suppressed error while {}: {}", context, e
)