Closed vreuter closed 3 months ago
In my code I have a decorator for functions that might raise exceptions and converts that into a function that returns a Result
:
_Exception = TypeVar("_Exception", bound=Exception)
@expression.curry_flip(1)
def wrap_exception(
fun: Callable[_P, _a],
exc: type[_Exception] | tuple[type[_Exception], ...] = Exception,
) -> Callable[_P, Result[_a, _Exception]]:
"""Wrap a function that might raise an Exception in a Result monad
Args:
fun (Callable[P, a]):
The function to be wrapped.
exc (Union[Tuple[Type[Exception], ...], Type[Exception]], optional):
The Exception types to be wrapped into the monad. Defaults to Exception.
Returns:
Callable[P, Result[a, Exception]]:
The decorated function.
Examples:
>>> @wrap_exception(ZeroDivisionError)
... def inverse(x: int) -> float:
... return 1 / x
>>> t: Result[float, ZeroDivisionError] = inverse(0)
"""
@functools.wraps(fun)
def _wrapper(*args: _P.args, **kwargs: _P.kwargs) -> Result[_a, _Exception]:
try:
return Result[_a, _Exception].Ok(fun(*args, **kwargs))
except exc as e:
return Result[_a, _Exception].Error(e)
return _wrapper
By default all exceptions are captured, but you can specify which exceptions should be captured. Would that solve your problem? Note that you can use this on existing functions too, such as pandas.read_excel
, like safe_read_excel = wrap_exception(FileNotFoundError)(pandas.read_excel)
.
Hey @Hugovdberg , indeed! This looks like a good solution. Mainly, I just want control flow to be by monadic combinators and/or pattern matchig, rather than by error handling, which this will provide :) And fantastic that the universe of caught exceptions is controllable w/ suitable default! Thanks a lot, I'm closing this for now.
Right now, it looks like a value of a
Try
subtype must be created directly, so normal error handling control flow is needed.What about a constructor that accepts a 0-arg callable (e.g., a fully parameterised function call), which is then invoked inside
try...except
logic, yielding anOk
-wrapped result if the call succeeds, and anError
-wrapped caught exception in the case of failure?