File tree Expand file tree Collapse file tree 7 files changed +132
-3
lines changed
Expand file tree Collapse file tree 7 files changed +132
-3
lines changed Original file line number Diff line number Diff line change @@ -7,7 +7,10 @@ We follow Semantic Versions since the `0.1.0` release.
77
88### Features
99
10- - Adds ` compose ` function
10+ - Adds ` compose ` helper function
11+ - Adds public API to ` import returns `
12+ - Adds ` raise_exception ` helper function
13+ - Adds full traceback to ` .unwrap() `
1114
1215
1316### Misc
Original file line number Diff line number Diff line change @@ -221,6 +221,44 @@ Composition is also type-safe.
221221The only limitation is that we only support
222222functions with one argument and one return to be composed.
223223
224+
225+ raise_exception
226+ ---------------
227+
228+ Sometimes you really want to reraise an exception from ``Failure[Exception] ``
229+ due to some existing API (or a dirty hack).
230+
231+ We allow you to do that with ease!
232+
233+ .. code :: python
234+
235+ from returns.functions import raise_exception
236+
237+ class CreateAccountAndUser (object ):
238+ """ Creates new Account-User pair."""
239+
240+ @pipeline
241+ def __call__ (self , username : str ) -> ... :
242+ """ Imagine, that you need to reraise ValidationErrors due to API."""
243+ user_schema = self ._validate_user(
244+ username,
245+ ).fix(
246+ # What happens here is interesting, since you do not let your
247+ # unwrap to fail with UnwrapFailedError, but instead
248+ # allows you to reraise a wrapped exception.
249+ # In this case `ValidationError()` will be thrown
250+ # before `UnwrapFailedError`
251+ raise_exception,
252+ ).unwrap()
253+
254+ def _validate_user (
255+ self , username : str ,
256+ ) -> Result[' User' , ValidationError]:
257+ ...
258+
259+ Use this with caution. We try to remove exceptions from our code base.
260+ Original proposal is `here <https://github.com/dry-python/returns/issues/56 >`_.
261+
224262API Reference
225263-------------
226264
Original file line number Diff line number Diff line change 11# -*- coding: utf-8 -*-
2+
3+ """
4+ We define public API here.
5+
6+ So, later our code can be used like so:
7+
8+ .. code:: python
9+
10+ import returns
11+ result: returns.Result[int, str]
12+
13+ See: https://github.com/dry-python/returns/issues/73
14+ """
15+
16+ from returns .functions import compose , safe , pipeline
17+ from returns .result import Failure , Result , Success
18+ from returns .primitives .exceptions import UnwrapFailedError
19+
20+ __all__ = ( # noqa: Z410
21+ 'compose' ,
22+ 'safe' ,
23+ 'pipeline' ,
24+ 'Failure' ,
25+ 'Result' ,
26+ 'Success' ,
27+ 'UnwrapFailedError' ,
28+ )
Original file line number Diff line number Diff line change @@ -56,9 +56,29 @@ def compose(first, second):
5656 """
5757 Allows function composition.
5858
59- Works as: second . first
59+ Works as: `` second . first``
6060 You can read it as "second after first".
6161
6262 We can only compose functions with one argument and one return.
6363 """
6464 return lambda argument : second (first (argument ))
65+
66+
67+ def raise_exception (exception ):
68+ """
69+ Helper function to raise exceptions as a function.
70+
71+ That's how it can be used:
72+
73+ .. code:: python
74+
75+ from returns.functions import raise_exception
76+
77+ # Some operation result:
78+ user: Failure[UserDoesNotExistError]
79+ # Here we unwrap internal exception and raise it:
80+ user.fix(raise_exception)
81+
82+ See: https://github.com/dry-python/returns/issues/56
83+ """
84+ raise exception
Original file line number Diff line number Diff line change 11# -*- coding: utf-8 -*-
22
3- from typing import Callable , TypeVar
3+ from typing import Callable , NoReturn , TypeVar
44
55from returns .primitives .container import Container
66from returns .result import Result
@@ -39,3 +39,7 @@ def compose(
3939 second : Callable [[_SecondType ], _ThirdType ],
4040) -> Callable [[_FirstType ], _ThirdType ]:
4141 ...
42+
43+
44+ def raise_exception (exception : Exception ) -> NoReturn :
45+ ...
Original file line number Diff line number Diff line change @@ -25,6 +25,8 @@ max-methods = 8
2525per-file-ignores =
2626 # Disable some pydocstyle checks for package:
2727 returns/**/*.py: D104
28+ # Disable imports in `__init__.py`:
29+ returns/__init__.py: F401, Z412
2830 # There are multiple assert's in tests:
2931 tests/**/test_*.py: S101
3032 # Disable some pydocstyle checks globally:
Original file line number Diff line number Diff line change 1+ # -*- coding: utf-8 -*-
2+
3+ from typing import Type
4+
5+ import pytest
6+
7+ from returns .functions import raise_exception
8+ from returns .result import Failure , Success
9+
10+
11+ class _CustomException (Exception ):
12+ """Just for the test."""
13+
14+
15+ @pytest .mark .parametrize ('exception_type' , [
16+ TypeError ,
17+ ValueError ,
18+ _CustomException ,
19+ ])
20+ def test_raise_regular_exception (exception_type : Type [Exception ]):
21+ """Ensures that regular exception can be thrown."""
22+ with pytest .raises (exception_type ):
23+ raise_exception (exception_type ())
24+
25+
26+ def test_failure_can_be_fixed ():
27+ """Ensures that exceptions can work with Failures."""
28+ failure = Failure (ValueError ('Message' ))
29+ with pytest .raises (ValueError ):
30+ failure .fix (raise_exception )
31+
32+
33+ def test_success_is_not_touched ():
34+ """Ensures that exceptions can work with Success."""
35+ assert Success (1 ).fix (raise_exception ) == Success (1 )
You can’t perform that action at this time.
0 commit comments