Skip to content

Commit e1b1220

Browse files
committed
Adds .failure() method
1 parent a0ddbc1 commit e1b1220

File tree

8 files changed

+80
-0
lines changed

8 files changed

+80
-0
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ We follow Semantic Versions since the `0.1.0` release.
1111
- Adds methods to work with failures
1212
- Adds `safe` decorator to convert exceptions to `Either` monad
1313
- Adds `is_successful()` function to detect if your result is a success
14+
- Adds `failure()` method to unwrap values from failed monads
1415

1516
### Bugfixes
1617

docs/pages/monad.rst

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,21 @@ inner state of monads into a regular types:
139139
140140
The most user-friendly way to use ``unwrap`` method is with :ref:`do-notation`.
141141

142+
For failing monads you can
143+
use :func:`Monad.failure <dry_monads.primitives.monad.Monad.failure>`
144+
to unwrap failed state:
145+
146+
.. code:: python
147+
148+
Failure(1).failure()
149+
# => 1
150+
151+
Success(1).failure()
152+
# => Traceback (most recent call last): UnwrapFailedError
153+
154+
Be careful, since this method will raise an exception
155+
when you try to ``failure`` a successful monad.
156+
142157
Immutability
143158
------------
144159

dry_monads/either.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,10 @@ def unwrap(self) -> NoReturn:
9595
"""Raises an exception, since it does not have a value inside."""
9696
raise UnwrapFailedError(self)
9797

98+
def failure(self) -> ErrorType:
99+
"""Unwraps inner error value from failed monad."""
100+
return self._inner_value
101+
98102

99103
@final
100104
class Right(Either[ValueType, Any], Monad[ValueType]):
@@ -154,6 +158,10 @@ def unwrap(self) -> ValueType:
154158
"""Returns the unwrapped value from the inside of this monad."""
155159
return self._inner_value
156160

161+
def failure(self) -> NoReturn:
162+
"""Raises an exception, since it does not have an error inside."""
163+
raise UnwrapFailedError(self)
164+
157165

158166
# Useful aliases for end users:
159167

dry_monads/maybe.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,10 @@ def unwrap(self) -> NoReturn:
9494
"""Raises an exception, since it does not have a value inside."""
9595
raise UnwrapFailedError(self)
9696

97+
def failure(self) -> None:
98+
"""Unwraps inner error value from failed monad."""
99+
return self._inner_value
100+
97101

98102
@final
99103
class Some(Maybe[ValueType]):
@@ -152,3 +156,7 @@ def value_or(self, default_value: NewValueType) -> ValueType:
152156
def unwrap(self) -> ValueType:
153157
"""Returns the unwrapped value from the inside of this monad."""
154158
return self._inner_value
159+
160+
def failure(self) -> NoReturn:
161+
"""Raises an exception, since it does not have an error inside."""
162+
raise UnwrapFailedError(self)

dry_monads/primitives/monad.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,5 +112,16 @@ def unwrap(self) -> ValueType: # pragma: no cover
112112
113113
Should be redefined for ones that actually have values.
114114
And for ones that raise an exception for no values.
115+
116+
This method is the opposite of :meth:`~failure`.
117+
"""
118+
raise NotImplementedError()
119+
120+
@abstractmethod
121+
def failure(self): # pragma: no cover
122+
"""
123+
Custom magic method to unwrap inner value from the failed monad.
124+
125+
This method is the opposite of :meth:`~unwrap`.
115126
"""
116127
raise NotImplementedError()

setup.cfg

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@ doctests = True
1919
enable-extensions = G
2020
isort-show-traceback = True
2121

22+
# wemake-python-styleguide
23+
max-methods = 8
24+
2225
per-file-ignores =
2326
# Disable some pydocstyle checks for package:
2427
dry_monads/**/*.py: D104
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# -*- coding: utf-8 -*-
2+
3+
import pytest
4+
5+
from dry_monads.either import Left, Right
6+
from dry_monads.primitives.exceptions import UnwrapFailedError
7+
8+
9+
def test_unwrap_success():
10+
"""Ensures that unwrap works for Right monad."""
11+
with pytest.raises(UnwrapFailedError):
12+
assert Right(5).failure()
13+
14+
15+
def test_unwrap_failure():
16+
"""Ensures that unwrap works for Left monad."""
17+
assert Left(5).failure() == 5
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# -*- coding: utf-8 -*-
2+
3+
import pytest
4+
5+
from dry_monads.maybe import Nothing, Some
6+
from dry_monads.primitives.exceptions import UnwrapFailedError
7+
8+
9+
def test_unwrap_success():
10+
"""Ensures that unwrap works for Some monad."""
11+
with pytest.raises(UnwrapFailedError):
12+
assert Some(1).failure()
13+
14+
15+
def test_unwrap_failure():
16+
"""Ensures that unwrap works for Nothing monad."""
17+
assert Nothing().failure() is None # type: ignore

0 commit comments

Comments
 (0)