Error Handling Decorator for Handlers

Wrap handler functions in a decorator that converts known exceptions into structured error results while letting unexpected errors propagate.

PythonResilience

Code

snippet
import functools
from typing import Any, Callable, Dict, Tuple, Type, TypeVar

T = TypeVar("T")


def handle_errors(
    known: Tuple[Type[BaseException], ...],
) -> Callable[[Callable[..., T]], Callable[..., Any]]:
    def decorator(func: Callable[..., T]) -> Callable[..., Any]:
        @functools.wraps(func)
        def wrapper(*args: Any, **kwargs: Any) -> Dict[str, Any]:
            try:
                return {"ok": True, "value": func(*args, **kwargs)}
            except known as error:
                return {"ok": False, "error": str(error)}

        return wrapper

    return decorator


@handle_errors((ValueError, KeyError))
def parse_age(raw: str) -> int:
    age = int(raw)
    if age < 0:
        raise ValueError("age must be positive")
    return age