Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement the catch utility decorator #16

Merged
merged 3 commits into from
Jan 24, 2021
Merged

Conversation

mlw214
Copy link
Contributor

@mlw214 mlw214 commented Jan 6, 2021

Implements the utility decorator catch per the discussion in #5.

@mlw214
Copy link
Contributor Author

mlw214 commented Jan 6, 2021

@dbrattli please let me know if there's anything you want me to add, remove, or correct!

@codecov
Copy link

codecov bot commented Jan 6, 2021

Codecov Report

Merging #16 (1b4ccf7) into main (35d14a6) will increase coverage by 0.09%.
The diff coverage is 100.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%> (ø)

Copy link
Collaborator

@erlendvollset erlendvollset left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks useful 👍

expression/extra/result/catch.py Outdated Show resolved Hide resolved
@erlendvollset
Copy link
Collaborator

erlendvollset commented Jan 16, 2021

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()

@dbrattli
Copy link
Owner

This is great! I also like the suggestion by @erlendvollset but we could do that as a separate PR to avoid blocking this PR.

Copy link
Owner

@dbrattli dbrattli left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great work!

@dbrattli dbrattli merged commit 9018f55 into dbrattli:main Jan 24, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants