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.
7
7
8
8
### Features
9
9
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() `
11
14
12
15
13
16
### Misc
Original file line number Diff line number Diff line change @@ -221,6 +221,44 @@ Composition is also type-safe.
221
221
The only limitation is that we only support
222
222
functions with one argument and one return to be composed.
223
223
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
+
224
262
API Reference
225
263
-------------
226
264
Original file line number Diff line number Diff line change 1
1
# -*- 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):
56
56
"""
57
57
Allows function composition.
58
58
59
- Works as: second . first
59
+ Works as: `` second . first``
60
60
You can read it as "second after first".
61
61
62
62
We can only compose functions with one argument and one return.
63
63
"""
64
64
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 1
1
# -*- coding: utf-8 -*-
2
2
3
- from typing import Callable , TypeVar
3
+ from typing import Callable , NoReturn , TypeVar
4
4
5
5
from returns .primitives .container import Container
6
6
from returns .result import Result
@@ -39,3 +39,7 @@ def compose(
39
39
second : Callable [[_SecondType ], _ThirdType ],
40
40
) -> Callable [[_FirstType ], _ThirdType ]:
41
41
...
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
25
25
per-file-ignores =
26
26
# Disable some pydocstyle checks for package:
27
27
returns/**/*.py: D104
28
+ # Disable imports in `__init__.py`:
29
+ returns/__init__.py: F401, Z412
28
30
# There are multiple assert's in tests:
29
31
tests/**/test_*.py: S101
30
32
# 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