Skip to content

Commit e96a354

Browse files
authored
add Partition #1905 (#1908)
1 parent e444ea7 commit e96a354

File tree

6 files changed

+121
-0
lines changed

6 files changed

+121
-0
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,11 @@ See [0Ver](https://0ver.org/).
1414
- Improve inference of `ResultLike` objects when exception catching
1515
decorator is applied with explicit exception types
1616
- Add picky exceptions to `impure_safe` decorator like `safe` has. Issue #1543
17+
- Add partition function to result module. Issue #1905
1718
- Adds `default_error` parameter to `returns.converters.maybe_to_result`,
1819
which provides a default error value for `Failure`
1920

21+
2022
### Misc
2123

2224
- Now requires `mypy>=1.11`

docs/pages/methods.rst

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,22 @@ Here's a full example:
7676
>>> error_handled = pointfree.bimap(lambda inr: inr + 1, lambda _: 0)(instance)
7777
>>> assert isinstance(methods.unwrap_or_failure(error_handled), int)
7878
79+
partition
80+
~~~~~~~~~
81+
82+
:func:`partition <returns.result.partition>` is used to convert
83+
list of :class:`~returns.interfaces.Unwrappable`
84+
instances like :class:`~returns.result.Result`,
85+
:class:`~returns.io.IOResult`, and :class:`~returns.maybe.Maybe`
86+
to a tuple of two lists: successes and failures.
87+
88+
.. code:: python
89+
90+
>>> from returns.result import Failure, Success
91+
>>> from returns.methods import partition
92+
>>> results = [Success(1), Failure(2), Success(3), Failure(4)]
93+
>>> partition(results)
94+
([1, 3], [2, 4])
7995
8096
API Reference
8197
-------------

returns/methods/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
from returns.methods.cond import cond as cond
2+
from returns.methods.partition import partition as partition
23
from returns.methods.unwrap_or_failure import (
34
unwrap_or_failure as unwrap_or_failure,
45
)

returns/methods/partition.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
2+
from typing import Iterable, List, TypeVar
3+
4+
from returns.interfaces.unwrappable import Unwrappable
5+
from returns.primitives.exceptions import UnwrapFailedError
6+
7+
_ValueType = TypeVar('_ValueType', covariant=True)
8+
_ErrorType = TypeVar('_ErrorType', covariant=True)
9+
10+
11+
def partition(
12+
containers: Iterable[
13+
Unwrappable[_ValueType, _ErrorType],
14+
],
15+
) -> tuple[List[_ValueType], List[_ErrorType]]:
16+
"""
17+
Partition a list of unwrappables into successful and failed values.
18+
19+
Preserves order.
20+
21+
.. code:: python
22+
23+
>>> from returns.result import Failure, Success
24+
>>> from returns.methods import partition
25+
26+
>>> results = [Success(1), Failure(2), Success(3), Failure(4)]
27+
>>> partition(results)
28+
([1, 3], [2, 4])
29+
30+
"""
31+
successes: list[_ValueType] = []
32+
failures: list[_ErrorType] = []
33+
for container in containers:
34+
try:
35+
successes.append(container.unwrap())
36+
except UnwrapFailedError:
37+
failures.append(container.failure())
38+
return successes, failures
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
2+
import pytest
3+
4+
from returns.io import IO, IOResult
5+
from returns.maybe import Nothing, Some
6+
from returns.methods import partition
7+
from returns.result import Failure, Success
8+
9+
10+
@pytest.mark.parametrize(('containers', 'expected'), [
11+
(
12+
(Success(1), Success(2), Failure(None), Success(3)),
13+
([1, 2, 3], [None]),
14+
),
15+
(
16+
(
17+
IOResult.from_value(1),
18+
IOResult.from_failure(2),
19+
IOResult.from_value(3),
20+
IOResult.from_failure(4),
21+
),
22+
([IO(1), IO(3)], [IO(2), IO(4)]),
23+
),
24+
(
25+
(Some(1), Some(2), Nothing),
26+
([1, 2], [None]),
27+
),
28+
((), ([], [])),
29+
])
30+
def test_partition(containers, expected):
31+
"""Test partition function."""
32+
assert partition(containers) == expected
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
- case: partition_result
2+
disable_cache: false
3+
main: |
4+
from typing import List
5+
from returns.result import Success, Failure, Result
6+
from returns.methods import partition
7+
8+
x: List[Result[int, str]]
9+
reveal_type(partition(x)) # N: Revealed type is "Tuple[builtins.list[builtins.int], builtins.list[builtins.str]]"
10+
11+
- case: partition_io_results
12+
disable_cache: false
13+
main: |
14+
from typing import Tuple
15+
from returns.result import Success, Failure
16+
from returns.methods import partition
17+
from returns.io import IO, IOResult, IOSuccess
18+
19+
x: Tuple[IOResult[int, str], IOResult[int, str]]
20+
reveal_type(partition(x)) # N: Revealed type is "Tuple[builtins.list[returns.io.IO[builtins.int]], builtins.list[returns.io.IO[builtins.str]]]"
21+
22+
- case: partition_maybe
23+
disable_cache: false
24+
main: |
25+
from typing import List, Tuple
26+
from returns.maybe import Maybe
27+
from returns.methods import partition
28+
29+
x: List[Maybe[int]]
30+
31+
reveal_type(partition(x)) # N: Revealed type is "Tuple[builtins.list[builtins.int], builtins.list[None]]"
32+

0 commit comments

Comments
 (0)