import sys import logging import traceback from abc import ABC from typing import Any, Callable from enum import Enum logger = logging.getLogger("") class SilentResultStatus(Enum): OK = "OK" ERROR = "ERROR" def __bool__(self): return self == SilentResultStatus.OK class SilentResult(ABC): status: SilentResultStatus result: Any def __init__(self, content, *args, **kwargs): self.content = content self.args = args self.kwargs = kwargs def __bool__(self): return bool(self.status) class OKResult(SilentResult): status = SilentResultStatus.OK class ErrorResult(SilentResult): status = SilentResultStatus.ERROR def silent(f: Callable): """Deco to wrap all errors from wrapped function. Instead, the original result returns tuple of: result status, identifier of item, result or exception depending on the result status. """ async def wrapped(*args, **kwargs) -> SilentResult: try: result = await f(*args, **kwargs) except Exception as exc: logger.error( f"{f.__name__} got {exc} hidden by silent handler.\n", traceback.format_exception(*sys.exc_info()) + traceback.format_stack(), ) return ErrorResult(exc, *args, **kwargs) return OKResult(result, *args, **kwargs) return wrapped