Skip to content

Commit 6ae2810

Browse files
authored
WIP: rewrites types for Result monad (#86)
* WIP: rewrites types for Result monad * WIP: rewrites types for Result monad * Adds docs * Adds docs
1 parent 461a683 commit 6ae2810

18 files changed

+273
-286
lines changed

CHANGELOG.md

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,19 @@ We follow Semantic Versions since the `0.1.0` release.
77

88
### Features
99

10-
- New types introduced: `FixableContainer` and `ValueUnwrapContainer`
10+
- Complete rewrite of `Result` types
11+
- Partial API change, now `Success` and `Failure` are not types, but functions
12+
- New internal types introduced: `FixableContainer` and `ValueUnwrapContainer`
13+
14+
### Bugfixes
15+
16+
- Fixes issue when you could return `IO` container from `Result.bind`
17+
- Fixes `@pipeline` return type
1118

1219
### Misc
1320

1421
- Improved docs about `IO` and `Container` concept
22+
- Adds docs about container composition
1523

1624

1725
## 0.7.0

docs/pages/container.rst

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -53,22 +53,23 @@ is used to literally bind two different containers together.
5353
def may_fail(user_id: int) -> Result[int, str]:
5454
...
5555
56-
result = Success(1).bind(may_fail)
57-
# => Either Success[int] or Failure[str]
56+
# Can be assumed as either Success[int] or Failure[str]:
57+
result: Result[int, str] = Success(1).bind(may_fail)
5858
5959
And we have :func:`.map <returns.primitives.container.Container.map>`
6060
to use containers with regular functions.
6161

6262
.. code:: python
6363
64-
from returns.result import Success
64+
from typing import Any
65+
from returns.result import Success, Result
6566
6667
def double(state: int) -> int:
6768
return state * 2
6869
69-
result = Success(1).map(double)
70+
result: Result[int, Any] = Success(1).map(double)
7071
# => Success(2)
71-
result.map(lambda state: state + 1)
72+
result: Result[int, Any] = result.map(lambda state: state + 1)
7273
# => Success(3)
7374
7475
The same work with built-in functions as well:
@@ -144,12 +145,12 @@ during the pipeline execution:
144145

145146
.. code:: python
146147
147-
from returns.result import Failure
148+
from returns.result import Failure, Result
148149
149150
def double(state: int) -> float:
150151
return state * 2.0
151152
152-
Failure(1).fix(double)
153+
result: Result[float, int] = Failure(1).fix(double)
153154
# => Success(2.0)
154155
155156
``rescue`` should return one of ``Success`` or ``Failure`` types.
@@ -164,12 +165,17 @@ It can also rescue your flow and get on the successful track again:
164165
return Success(0)
165166
return Failure(state)
166167
167-
Failure(ZeroDivisionError()).rescue(tolerate_exception)
168+
result: Result[int, Exception] = Failure(
169+
ZeroDivisionError(),
170+
).rescue(tolerate_exception)
168171
# => Success(0)
169172
170-
Failure(ValueError()).rescue(tolerate_exception)
173+
result2: Result[int, Exception] = Failure(
174+
ValueError(),
175+
).rescue(tolerate_exception)
171176
# => Failure(ValueError())
172177
178+
173179
Note::
174180

175181
Not all containers support these methods.
@@ -257,6 +263,10 @@ when they install our application.
257263
However, this is still good old ``python`` type system,
258264
and it has its drawbacks.
259265

266+
You can have a look at the suggested ``mypy``
267+
`configuration <https://github.com/dry-python/returns/blob/master/setup.cfg>`_
268+
in our own repository.
269+
260270

261271
API Reference
262272
-------------

docs/pages/functions.rst

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -41,21 +41,22 @@ We allow you to do that with ease!
4141
@pipeline
4242
def __call__(self, username: str) -> ...:
4343
"""Imagine, that you need to reraise ValidationErrors due to API."""
44-
user_schema = self._validate_user(
45-
username,
44+
return self._validate_user(
45+
username,
46+
# TODO: change in #84 to `.map_failure()`
4647
).fix(
47-
# What happens here is interesting, since you do not let your
48-
# unwrap to fail with UnwrapFailedError, but instead
49-
# allows you to reraise a wrapped exception.
50-
# In this case `ValidationError()` will be thrown
51-
# before `UnwrapFailedError`
52-
raise_exception,
53-
).unwrap()
48+
# What happens here is interesting, since you do not let your
49+
# unwrap to fail with UnwrapFailedError, but instead
50+
# allows you to reraise a wrapped exception.
51+
# In this case `ValidationError()` will be thrown
52+
# before `UnwrapFailedError`
53+
raise_exception,
54+
)
5455
5556
def _validate_user(
56-
self, username: str,
57+
self, username: str,
5758
) -> Result['User', ValidationError]:
58-
...
59+
...
5960
6061
Use this with caution. We try to remove exceptions from our code base.
6162
Original proposal is `here <https://github.com/dry-python/returns/issues/56>`_.

docs/pages/result.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,7 @@ Supports both async and regular functions.
196196
197197
from returns.result import safe
198198
199-
@safe
199+
@safe # Will convert type to: Callable[[int], Result[float, Exception]]
200200
def divide(number: int) -> float:
201201
return number / number
202202

0 commit comments

Comments
 (0)