Closed mlw214 closed 3 years ago
@dbrattli please let me know if there's anything you want me to add, remove, or correct!
Merging #16 (1b4ccf7) into main (35d14a6) will increase coverage by
0.09%
. The diff coverage is100.00%
.
@@ Coverage Diff @@
## main #16 +/- ##
==========================================
+ Coverage 80.23% 80.32% +0.09%
==========================================
Files 37 38 +1
Lines 2130 2140 +10
==========================================
+ Hits 1709 1719 +10
Misses 421 421
Impacted Files | Coverage Δ | |
---|---|---|
expression/extra/result/__init__.py | 100.00% <100.00%> (ø) |
|
expression/extra/result/catch.py | 100.00% <100.00%> (ø) |
Could also support multiple exception types without chaining decorators by packing the exception parameter like this:
(note use of /
separator in overload signatures for enforcing positional-only parameters)
TSource = TypeVar("TSource")
TError1 = TypeVar("TError1", bound=Exception)
TError2 = TypeVar("TError2", bound=Exception)
TError3 = TypeVar("TError3", bound=Exception)
TError4 = TypeVar("TError4", bound=Exception)
@overload
def catch(__exc1: Type[TError1], /) -> Callable[[Callable[..., TSource]], Callable[..., Result[TSource, TError1]]]:
...
@overload
def catch(
__exc1: Type[TError1], __exc2: Type[TError2], /
) -> Callable[[Callable[..., TSource]], Callable[..., Result[TSource, Union[TError1, TError2]]]]:
...
@overload
def catch(
__exc1: Type[TError1], __exc2: Type[TError2], __exc3: Type[TError3], /
) -> Callable[[Callable[..., TSource]], Callable[..., Result[TSource, Union[TError1, TError2, TError3]]]]:
...
@overload
def catch(
__exc1: Type[TError1], __exc2: Type[TError2], __exc3: Type[TError3], __exc4: Type[TError4], /
) -> Callable[[Callable[..., TSource]], Callable[..., Result[TSource, Union[TError1, TError2, TError3, TError4]]]]:
...
def catch(*exception: Type[Exception]) -> Callable[[Callable[..., TSource]], Callable[..., Result[TSource, Exception]]]:
def decorator(fn: Callable[..., TSource]) -> Callable[..., Result[TSource, Exception]]:
@wraps(fn)
def wrapper(*args: Any, **kwargs: Any) -> Result[TSource, Exception]:
try:
out = fn(*args, **kwargs)
except exception as exn:
return Error(cast(Exception, exn))
else:
if isinstance(out, Result):
return cast(Result[TSource, Exception], out)
return Ok(out)
return wrapper
return decorator
Usage example:
@catch(ValueError, TypeError)
def foo() -> int:
raise ValueError()
This is great! I also like the suggestion by @erlendvollset but we could do that as a separate PR to avoid blocking this PR.
Implements the utility decorator
catch
per the discussion in #5.