Skip to content

Commit b657c32

Browse files
committed
Adds squash_context, closes #234
1 parent 06baab3 commit b657c32

File tree

15 files changed

+404
-219
lines changed

15 files changed

+404
-219
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ See [0Ver](https://0ver.org/).
1313
- **Breaking**: renames `join` to `flatten`, sorry!
1414
- **Breaking**: renames `box` to `bind` and moves it to `returns.pointfree`
1515
- **Breaking**: removes `Maybe.rescue` and `Maybe.fix` methods
16+
- **Breaking**: renames `io_squash` to `squash_io`
17+
and moves it to `returns.converters`
1618

1719
- Adds `rescue` pointfree function
1820
- Adds `ResultE` alias for `Result[..., Exception]`
@@ -50,6 +52,7 @@ See [0Ver](https://0ver.org/).
5052
methods for all `Result` realted classes
5153
- Adds `flow` function, which is similar to `pipe`
5254
- Adds `swap` coverter for `Result` and `IOResult`
55+
- Adds `squash_context` function to squash `RequiresContext` similar to `IO`
5356

5457

5558
### Bugfixes

docs/pages/converters.rst

Lines changed: 58 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -110,10 +110,59 @@ one for successful case, one for failing case.
110110
... return 0.0
111111
...
112112
113-
>>> coalesce_result(handle_success, handle_failure)(Success(1))
114-
0.5
115-
>>> coalesce_result(handle_success, handle_failure)(Failure(1))
116-
0.0
113+
>>> assert coalesce_result(handle_success, handle_failure)(Success(1)) == 0.5
114+
>>> assert coalesce_result(handle_success, handle_failure)(Failure(1)) == 0.0
115+
116+
117+
squash
118+
------
119+
120+
squash_io
121+
~~~~~~~~~
122+
123+
:func:`returns.converters.squash_io` function
124+
allows to squash several ``IO`` containers together.
125+
126+
That's how it works:
127+
128+
.. code:: python
129+
130+
>>> from returns.io import IO
131+
>>> from returns.converters import squash_io
132+
133+
>>> assert squash_io(IO('first'), IO('second')) == IO(('first', 'second'))
134+
>>> # => revealed type of this instance is `IO[Tuple[str, str]]`
135+
136+
It might be helpful if you want
137+
to work with mutliple ``IO`` instances at the same time.
138+
139+
This approach saves you you from multiple nested ``IO.map`` calls.
140+
You can work with tuples instead like so:
141+
142+
.. code:: python
143+
144+
>>> plus = squash_io(IO(1), IO('a')).map(lambda args: args[0] + len(args[1]))
145+
>>> assert plus == IO(3)
146+
147+
We support up to 9 typed parameters to this function.
148+
149+
squash_context
150+
~~~~~~~~~~~~~~
151+
152+
:func:`returns.converters.squash_context` is similar to ``squash_io``,
153+
but works with ``RequiresContext`` container.
154+
155+
.. code:: python
156+
157+
>>> from returns.context import RequiresContext
158+
>>> from returns.converters import squash_context
159+
160+
>>> assert squash_context(
161+
... RequiresContext.from_value(1),
162+
... RequiresContext.from_value('a'),
163+
... )(...) == RequiresContext.from_value((1, 'a'))(...)
164+
>>> # revealed type is: RequiresContext[Any, Tuple[int, str]]
165+
117166
118167
119168
API Reference
@@ -123,11 +172,12 @@ API Reference
123172

124173
.. autofunction:: returns.converters.flatten
125174

126-
.. autofunction:: returns.converters.coalesce_maybe
127-
128-
.. autofunction:: returns.converters.coalesce_result
175+
.. autofunction:: returns.converters.squash_io
129176

130-
.. autofunction:: returns.converters.coalesce_ioresult
177+
.. autofunction:: returns.converters.squash_context
131178

132179
.. automodule:: returns.converters
133180
:members:
181+
182+
.. autofunction:: returns.converters.coalesce_maybe
183+

docs/pages/io.rst

Lines changed: 1 addition & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -320,33 +320,7 @@ Use for impure operations that might fail.
320320
Helpers
321321
-------
322322

323-
io_squash
324-
~~~~~~~~~
325-
326-
This function allows to squash several ``IO`` containers together.
327-
328-
That's how it works:
329-
330-
.. code:: python
331-
332-
>>> from returns.io import IO, io_squash
333-
334-
>>> assert io_squash(IO('first'), IO('second')) == IO(('first', 'second'))
335-
>>> # => revealed type of this instance is `IO[Tuple[str, str]]`
336-
337-
It might be helpful if you want
338-
to work with mutliple ``IO`` instances at the same time.
339-
340-
This approach saves you you from multiple nested ``IO.map`` calls.
341-
You can work with tuples instead like so:
342-
343-
.. code:: python
344-
345-
>>> plus = io_squash(IO(1), IO(2)).map(lambda args: args[0] + args[1])
346-
>>> assert plus == IO(3)
347-
348-
We support up to 9 typed parameters to this function.
349-
323+
Don't forget to check out :ref:`converters`.
350324

351325
.. _unsafe_perform_io:
352326

returns/_generated/converters/coalesce.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@
5353
_FirstType = TypeVar('_FirstType')
5454

5555

56-
def _fold(success_handler, failure_handler):
56+
def _coalesce(success_handler, failure_handler):
5757
"""
5858
We need this function, because we cannot use a single typed function.
5959
@@ -72,7 +72,7 @@ def decorator(container):
7272
Callable[[_ErrorType], _FirstType],
7373
],
7474
Callable[[Result[_ValueType, _ErrorType]], _FirstType],
75-
] = _fold
75+
] = _coalesce
7676
_coalesce_result.__doc__ = __doc__
7777

7878
_coalesce_ioresult: Callable[
@@ -81,7 +81,7 @@ def decorator(container):
8181
Callable[[IO[_ErrorType]], IO[_FirstType]],
8282
],
8383
Callable[[IOResult[_ValueType, _ErrorType]], IO[_FirstType]],
84-
] = _fold
84+
] = _coalesce
8585
_coalesce_ioresult.__doc__ = __doc__
8686

8787
_coalesce_maybe: Callable[
@@ -90,5 +90,5 @@ def decorator(container):
9090
Callable[[None], _FirstType],
9191
],
9292
Callable[[Maybe[_ValueType]], _FirstType],
93-
] = _fold
93+
] = _coalesce
9494
_coalesce_maybe.__doc__ = __doc__
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
# -*- coding: utf-8 -*-
2+
3+
from returns.context import RequiresContext
4+
from returns.io import IO
5+
6+
7+
def _squash_io(*args):
8+
"""
9+
Unwraps ``IO`` values, merges them into tuple, and wraps back.
10+
11+
.. code:: python
12+
13+
>>> from returns.io import IO
14+
>>> from returns.converters import squash_io
15+
>>> assert squash_io(IO('a'), IO('b')) == IO(('a', 'b'))
16+
17+
Why this only exists for ``IO`` and ``RequiresContext``?
18+
Because these types represent real values, that do not possibly fail.
19+
20+
How would you, for example, squash two ``Result`` values?
21+
``Success(1)`` and ``Failure(2)`` would not give you a tuple when squashed.
22+
"""
23+
return IO(tuple(
24+
container._inner_value # noqa: WPS437
25+
for container in args
26+
))
27+
28+
29+
def _squash_context(*args):
30+
"""
31+
Unwraps ``RequiresContext`` values, merges them into tuple, and wraps back.
32+
33+
.. code:: python
34+
35+
>>> from returns.context import RequiresContext
36+
>>> from returns.converters import squash_context
37+
>>> assert squash_context(
38+
... RequiresContext.from_value(1),
39+
... RequiresContext.from_value('a'),
40+
... RequiresContext.from_value(True),
41+
... )(...) == RequiresContext.from_value((1, 'a', True))(...)
42+
43+
See :func:`returns.converters.squash_io` for more docs.
44+
"""
45+
return RequiresContext(lambda deps: tuple(
46+
func(deps)
47+
for func in args
48+
))

0 commit comments

Comments
 (0)