stdlibx-result 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- stdlibx_result-0.1.0/LICENSE +21 -0
- stdlibx_result-0.1.0/PKG-INFO +25 -0
- stdlibx_result-0.1.0/README.md +12 -0
- stdlibx_result-0.1.0/pyproject.toml +25 -0
- stdlibx_result-0.1.0/src/stdlibx/result/__init__.py +23 -0
- stdlibx_result-0.1.0/src/stdlibx/result/_errors.py +10 -0
- stdlibx_result-0.1.0/src/stdlibx/result/_result.py +101 -0
- stdlibx_result-0.1.0/src/stdlibx/result/_types.py +11 -0
- stdlibx_result-0.1.0/src/stdlibx/result/fn/__init__.py +57 -0
- stdlibx_result-0.1.0/src/stdlibx/result/fn/base.py +109 -0
- stdlibx_result-0.1.0/src/stdlibx/result/fn/collect.py +160 -0
- stdlibx_result-0.1.0/src/stdlibx/result/fn/option.py +25 -0
- stdlibx_result-0.1.0/src/stdlibx/result/methods/__init__.py +54 -0
- stdlibx_result-0.1.0/src/stdlibx/result/methods/base.py +150 -0
- stdlibx_result-0.1.0/src/stdlibx/result/methods/option.py +31 -0
- stdlibx_result-0.1.0/src/stdlibx/result/py.typed +0 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Lucino772
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: stdlibx-result
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: stdlibx-result
|
|
5
|
+
Author: Lucino772
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
License-File: LICENSE
|
|
8
|
+
Requires-Dist: typing-extensions>=4.10.0,<5
|
|
9
|
+
Requires-Python: >=3.9
|
|
10
|
+
Project-URL: Documentation, http://stdlibx.lucapalmi.com/
|
|
11
|
+
Project-URL: Repository, https://github.com/Lucino772/stdlibx
|
|
12
|
+
Description-Content-Type: text/markdown
|
|
13
|
+
|
|
14
|
+
[](https://github.com/Lucino772/stdlibx/actions/workflows/deploy-docs.yaml)
|
|
15
|
+
|
|
16
|
+
# stdlibx
|
|
17
|
+
**stdlibx** is a collection of small, focused Python utilities that simplify common programming patterns and help you write clearer, more composable code.
|
|
18
|
+
|
|
19
|
+
It provides practical tools for handling optional values, explicit error management, cancellation, composition, configuration, pattern matching, and reactive flows.
|
|
20
|
+
|
|
21
|
+
## Documentation
|
|
22
|
+
Checkout the [documentation](http://stdlibx.lucapalmi.com/)
|
|
23
|
+
|
|
24
|
+
## Licence
|
|
25
|
+
This project uses a **MIT** Licence [view](https://github.com/Lucino772/stdlibx/blob/main/LICENSE)
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
[](https://github.com/Lucino772/stdlibx/actions/workflows/deploy-docs.yaml)
|
|
2
|
+
|
|
3
|
+
# stdlibx
|
|
4
|
+
**stdlibx** is a collection of small, focused Python utilities that simplify common programming patterns and help you write clearer, more composable code.
|
|
5
|
+
|
|
6
|
+
It provides practical tools for handling optional values, explicit error management, cancellation, composition, configuration, pattern matching, and reactive flows.
|
|
7
|
+
|
|
8
|
+
## Documentation
|
|
9
|
+
Checkout the [documentation](http://stdlibx.lucapalmi.com/)
|
|
10
|
+
|
|
11
|
+
## Licence
|
|
12
|
+
This project uses a **MIT** Licence [view](https://github.com/Lucino772/stdlibx/blob/main/LICENSE)
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "stdlibx-result"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "stdlibx-result"
|
|
5
|
+
license = "MIT"
|
|
6
|
+
license-files = ["LICEN[CS]E*"]
|
|
7
|
+
readme = "README.md"
|
|
8
|
+
authors = [
|
|
9
|
+
{ name = "Lucino772" }
|
|
10
|
+
]
|
|
11
|
+
requires-python = ">=3.9"
|
|
12
|
+
dependencies = [
|
|
13
|
+
"typing_extensions>=4.10.0,<5"
|
|
14
|
+
]
|
|
15
|
+
|
|
16
|
+
[project.urls]
|
|
17
|
+
Documentation = "http://stdlibx.lucapalmi.com/"
|
|
18
|
+
Repository = "https://github.com/Lucino772/stdlibx"
|
|
19
|
+
|
|
20
|
+
[tool.uv.build-backend]
|
|
21
|
+
module-name = "stdlibx.result"
|
|
22
|
+
|
|
23
|
+
[build-system]
|
|
24
|
+
requires = ["uv_build>=0.9.28,<0.10.0"]
|
|
25
|
+
build-backend = "uv_build"
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
from stdlibx.result._errors import ResultError, ResultExpectError, ResultUnwrapError
|
|
2
|
+
from stdlibx.result._result import (
|
|
3
|
+
Error,
|
|
4
|
+
Ok,
|
|
5
|
+
Result,
|
|
6
|
+
as_result,
|
|
7
|
+
is_err,
|
|
8
|
+
is_ok,
|
|
9
|
+
result_of,
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
__all__ = [
|
|
13
|
+
"Error",
|
|
14
|
+
"Ok",
|
|
15
|
+
"Result",
|
|
16
|
+
"ResultError",
|
|
17
|
+
"ResultExpectError",
|
|
18
|
+
"ResultUnwrapError",
|
|
19
|
+
"as_result",
|
|
20
|
+
"is_err",
|
|
21
|
+
"is_ok",
|
|
22
|
+
"result_of",
|
|
23
|
+
]
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from functools import wraps
|
|
4
|
+
from typing import TYPE_CHECKING, Callable, Generic, Literal, TypeVar
|
|
5
|
+
|
|
6
|
+
from typing_extensions import ParamSpec, TypeAlias, TypeGuard
|
|
7
|
+
|
|
8
|
+
if TYPE_CHECKING:
|
|
9
|
+
from stdlibx.result._types import Operation
|
|
10
|
+
|
|
11
|
+
T = TypeVar("T")
|
|
12
|
+
E = TypeVar("E")
|
|
13
|
+
U = TypeVar("U")
|
|
14
|
+
P = ParamSpec("P")
|
|
15
|
+
_AnyException = TypeVar("_AnyException", bound=Exception)
|
|
16
|
+
|
|
17
|
+
Result: TypeAlias = "Ok[T, E] | Error[T, E]"
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def is_ok(result: Result[T, E]) -> TypeGuard[Ok[T, E]]:
|
|
21
|
+
return result.is_ok()
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def is_err(result: Result[T, E]) -> TypeGuard[Error[T, E]]:
|
|
25
|
+
return result.is_err()
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def result_of(
|
|
29
|
+
func: Callable[P, T], *args: P.args, **kwargs: P.kwargs
|
|
30
|
+
) -> Result[T, Exception]:
|
|
31
|
+
try:
|
|
32
|
+
return Ok(func(*args, **kwargs))
|
|
33
|
+
except Exception as e:
|
|
34
|
+
return Error(e)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def as_result(
|
|
38
|
+
func: Callable[P, T], exceptions: tuple[type[_AnyException], ...] = (Exception,)
|
|
39
|
+
) -> Callable[P, Result[T, _AnyException]]:
|
|
40
|
+
@wraps(func)
|
|
41
|
+
def _wrapped(*args: P.args, **kwargs: P.kwargs) -> Result[T, _AnyException]:
|
|
42
|
+
try:
|
|
43
|
+
return Ok(func(*args, **kwargs))
|
|
44
|
+
except exceptions as e:
|
|
45
|
+
return Error(e)
|
|
46
|
+
|
|
47
|
+
return _wrapped
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
class Ok(Generic[T, E]):
|
|
51
|
+
__match_args__ = ("value",)
|
|
52
|
+
__slots__ = ("value",)
|
|
53
|
+
|
|
54
|
+
value: T
|
|
55
|
+
|
|
56
|
+
def __init__(self, value: T) -> None:
|
|
57
|
+
self.value = value
|
|
58
|
+
|
|
59
|
+
def __repr__(self) -> str:
|
|
60
|
+
return f"Ok({self.value!r})"
|
|
61
|
+
|
|
62
|
+
def __eq__(self, other: object) -> bool:
|
|
63
|
+
if isinstance(other, Ok):
|
|
64
|
+
return other.value == self.value
|
|
65
|
+
return False
|
|
66
|
+
|
|
67
|
+
def is_ok(self) -> Literal[True]:
|
|
68
|
+
return True
|
|
69
|
+
|
|
70
|
+
def is_err(self) -> Literal[False]:
|
|
71
|
+
return False
|
|
72
|
+
|
|
73
|
+
def apply(self, operation: Operation[Result[T, E], U]) -> U:
|
|
74
|
+
return operation(self)
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
class Error(Generic[T, E]):
|
|
78
|
+
__match_args__ = ("error",)
|
|
79
|
+
__slots__ = ("error",)
|
|
80
|
+
|
|
81
|
+
error: E
|
|
82
|
+
|
|
83
|
+
def __init__(self, error: E) -> None:
|
|
84
|
+
self.error = error
|
|
85
|
+
|
|
86
|
+
def __repr__(self) -> str:
|
|
87
|
+
return f"Error({self.error!r})"
|
|
88
|
+
|
|
89
|
+
def __eq__(self, other: object) -> bool:
|
|
90
|
+
if isinstance(other, Error):
|
|
91
|
+
return other.error == self.error
|
|
92
|
+
return False
|
|
93
|
+
|
|
94
|
+
def is_ok(self) -> Literal[False]:
|
|
95
|
+
return False
|
|
96
|
+
|
|
97
|
+
def is_err(self) -> Literal[True]:
|
|
98
|
+
return True
|
|
99
|
+
|
|
100
|
+
def apply(self, operation: Operation[Result[T, E], U]) -> U:
|
|
101
|
+
return operation(self)
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
from stdlibx.result.fn.base import (
|
|
2
|
+
and_,
|
|
3
|
+
and_then,
|
|
4
|
+
expect,
|
|
5
|
+
expect_err,
|
|
6
|
+
flatten,
|
|
7
|
+
inspect,
|
|
8
|
+
inspect_err,
|
|
9
|
+
is_err_and,
|
|
10
|
+
is_ok_and,
|
|
11
|
+
map_,
|
|
12
|
+
map_err,
|
|
13
|
+
map_or,
|
|
14
|
+
map_or_else,
|
|
15
|
+
or_,
|
|
16
|
+
or_else,
|
|
17
|
+
unwrap,
|
|
18
|
+
unwrap_err,
|
|
19
|
+
unwrap_or,
|
|
20
|
+
unwrap_or_else,
|
|
21
|
+
unwrap_or_raise,
|
|
22
|
+
zipped,
|
|
23
|
+
)
|
|
24
|
+
from stdlibx.result.fn.collect import collect, collect_all
|
|
25
|
+
|
|
26
|
+
__all__ = [
|
|
27
|
+
"and_",
|
|
28
|
+
"and_then",
|
|
29
|
+
"collect",
|
|
30
|
+
"collect_all",
|
|
31
|
+
"expect",
|
|
32
|
+
"expect_err",
|
|
33
|
+
"flatten",
|
|
34
|
+
"inspect",
|
|
35
|
+
"inspect_err",
|
|
36
|
+
"is_err_and",
|
|
37
|
+
"is_ok_and",
|
|
38
|
+
"map_",
|
|
39
|
+
"map_err",
|
|
40
|
+
"map_or",
|
|
41
|
+
"map_or_else",
|
|
42
|
+
"or_",
|
|
43
|
+
"or_else",
|
|
44
|
+
"unwrap",
|
|
45
|
+
"unwrap_err",
|
|
46
|
+
"unwrap_or",
|
|
47
|
+
"unwrap_or_else",
|
|
48
|
+
"unwrap_or_raise",
|
|
49
|
+
"zipped",
|
|
50
|
+
]
|
|
51
|
+
|
|
52
|
+
try:
|
|
53
|
+
from stdlibx.result.fn.option import err, ok, transpose
|
|
54
|
+
|
|
55
|
+
__all__ += ["err", "ok", "transpose"]
|
|
56
|
+
except ImportError:
|
|
57
|
+
pass
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from functools import partial
|
|
4
|
+
from typing import TYPE_CHECKING, Callable, TypeVar, Union
|
|
5
|
+
|
|
6
|
+
from stdlibx.result import Result, methods
|
|
7
|
+
from typing_extensions import TypeVarTuple, Unpack
|
|
8
|
+
|
|
9
|
+
if TYPE_CHECKING:
|
|
10
|
+
from stdlibx.result._types import Operation
|
|
11
|
+
|
|
12
|
+
T = TypeVar("T")
|
|
13
|
+
E = TypeVar("E")
|
|
14
|
+
U = TypeVar("U")
|
|
15
|
+
F = TypeVar("F")
|
|
16
|
+
Ts = TypeVarTuple("Ts")
|
|
17
|
+
_AnyException = TypeVar("_AnyException", bound=Exception)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def is_ok_and(func: Callable[[T], bool]) -> Operation[Result[T, E], bool]:
|
|
21
|
+
return partial(methods.is_ok_and, func=func)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def is_err_and(func: Callable[[E], bool]) -> Operation[Result[T, E], bool]:
|
|
25
|
+
return partial(methods.is_err_and, func=func)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def map_(func: Callable[[T], U]) -> Operation[Result[T, E], Result[U, E]]:
|
|
29
|
+
return partial(methods.map_, func=func)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def map_or(default: U, func: Callable[[T], U]) -> Operation[Result[T, E], U]:
|
|
33
|
+
return partial(methods.map_or, default=default, func=func)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def map_or_else(
|
|
37
|
+
default: Callable[[E], U], func: Callable[[T], U]
|
|
38
|
+
) -> Operation[Result[T, E], U]:
|
|
39
|
+
return partial(methods.map_or_else, default=default, func=func)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def map_err(func: Callable[[E], F]) -> Operation[Result[T, E], Result[T, F]]:
|
|
43
|
+
return partial(methods.map_err, func=func)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def inspect(func: Callable[[T], None]) -> Operation[Result[T, E], Result[T, E]]:
|
|
47
|
+
return partial(methods.inspect, func=func)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def inspect_err(func: Callable[[E], None]) -> Operation[Result[T, E], Result[T, E]]:
|
|
51
|
+
return partial(methods.inspect_err, func=func)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def expect(msg: str) -> Operation[Result[T, E], T]:
|
|
55
|
+
return partial(methods.expect, msg=msg)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def unwrap() -> Operation[Result[T, E], T]:
|
|
59
|
+
return methods.unwrap
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def expect_err(msg: str) -> Operation[Result[T, E], E]:
|
|
63
|
+
return partial(methods.expect_err, msg=msg)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def unwrap_err() -> Operation[Result[T, E], E]:
|
|
67
|
+
return methods.unwrap_err
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def and_(other: Result[U, F]) -> Operation[Result[T, E], Result[U, Union[E, F]]]:
|
|
71
|
+
return partial(methods.and_, other=other)
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def and_then(
|
|
75
|
+
func: Callable[[T], Result[U, F]],
|
|
76
|
+
) -> Operation[Result[T, E], Result[U, Union[E, F]]]:
|
|
77
|
+
return partial(methods.and_then, func=func)
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def or_(default: Result[T, F]) -> Operation[Result[T, E], Result[T, F]]:
|
|
81
|
+
return partial(methods.or_, default=default)
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def or_else(
|
|
85
|
+
default: Callable[[E], Result[T, F]],
|
|
86
|
+
) -> Operation[Result[T, E], Result[T, F]]:
|
|
87
|
+
return partial(methods.or_else, default=default)
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def unwrap_or(default: T) -> Operation[Result[T, E], T]:
|
|
91
|
+
return partial(methods.unwrap_or, default=default)
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def unwrap_or_else(default: Callable[[E], T]) -> Operation[Result[T, E], T]:
|
|
95
|
+
return partial(methods.unwrap_or_else, default=default)
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def unwrap_or_raise() -> Operation[Result[T, _AnyException], T]:
|
|
99
|
+
return methods.unwrap_or_raise
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def flatten() -> Operation[Result[Result[T, E], F], Result[T, Union[E, F]]]:
|
|
103
|
+
return methods.flatten
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def zipped(
|
|
107
|
+
func: Callable[[Unpack[Ts]], Result[U, E]],
|
|
108
|
+
) -> Operation[Result[tuple[Unpack[Ts]], E], Result[tuple[Unpack[Ts], U], E]]:
|
|
109
|
+
return partial(methods.zipped, func=func)
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import functools
|
|
4
|
+
from typing import Any, Iterable, TypeVar, Union, overload
|
|
5
|
+
|
|
6
|
+
from stdlibx.result._result import Error, Ok, Result, is_err
|
|
7
|
+
|
|
8
|
+
T = TypeVar("T")
|
|
9
|
+
E = TypeVar("E")
|
|
10
|
+
|
|
11
|
+
T1 = TypeVar("T1")
|
|
12
|
+
T2 = TypeVar("T2")
|
|
13
|
+
T3 = TypeVar("T3")
|
|
14
|
+
T4 = TypeVar("T4")
|
|
15
|
+
T5 = TypeVar("T5")
|
|
16
|
+
T6 = TypeVar("T6")
|
|
17
|
+
T7 = TypeVar("T7")
|
|
18
|
+
T8 = TypeVar("T8")
|
|
19
|
+
T9 = TypeVar("T9")
|
|
20
|
+
|
|
21
|
+
E1 = TypeVar("E1")
|
|
22
|
+
E2 = TypeVar("E2")
|
|
23
|
+
E3 = TypeVar("E3")
|
|
24
|
+
E4 = TypeVar("E4")
|
|
25
|
+
E5 = TypeVar("E5")
|
|
26
|
+
E6 = TypeVar("E6")
|
|
27
|
+
E7 = TypeVar("E7")
|
|
28
|
+
E8 = TypeVar("E8")
|
|
29
|
+
E9 = TypeVar("E9")
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
@overload
|
|
33
|
+
def collect(
|
|
34
|
+
a: Result[T1, E1],
|
|
35
|
+
b: Result[T2, E2],
|
|
36
|
+
/,
|
|
37
|
+
) -> Result[tuple[T1, T2], Union[E1, E2]]: ...
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
@overload
|
|
41
|
+
def collect(
|
|
42
|
+
a: Result[T1, E1],
|
|
43
|
+
b: Result[T2, E2],
|
|
44
|
+
c: Result[T3, E3],
|
|
45
|
+
/,
|
|
46
|
+
) -> Result[tuple[T1, T2, T3], Union[E1, E2, E3]]: ...
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
@overload
|
|
50
|
+
def collect(
|
|
51
|
+
a: Result[T1, E1],
|
|
52
|
+
b: Result[T2, E2],
|
|
53
|
+
c: Result[T3, E3],
|
|
54
|
+
d: Result[T4, E4],
|
|
55
|
+
/,
|
|
56
|
+
) -> Result[tuple[T1, T2, T3, T4], Union[E1, E2, E3, E4]]: ...
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
@overload
|
|
60
|
+
def collect(
|
|
61
|
+
a: Result[T1, E1],
|
|
62
|
+
b: Result[T2, E2],
|
|
63
|
+
c: Result[T3, E3],
|
|
64
|
+
d: Result[T4, E4],
|
|
65
|
+
e: Result[T5, E5],
|
|
66
|
+
/,
|
|
67
|
+
) -> Result[tuple[T1, T2, T3, T4, T5], Union[E1, E2, E3, E4, E5]]: ...
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
@overload
|
|
71
|
+
def collect(
|
|
72
|
+
a: Result[T1, E1],
|
|
73
|
+
b: Result[T2, E2],
|
|
74
|
+
c: Result[T3, E3],
|
|
75
|
+
d: Result[T4, E4],
|
|
76
|
+
e: Result[T5, E5],
|
|
77
|
+
f: Result[T6, E6],
|
|
78
|
+
/,
|
|
79
|
+
) -> Result[tuple[T1, T2, T3, T4, T5, T6], Union[E1, E2, E3, E4, E5, E6]]: ...
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
@overload
|
|
83
|
+
def collect(
|
|
84
|
+
a: Result[T1, E1],
|
|
85
|
+
b: Result[T2, E2],
|
|
86
|
+
c: Result[T3, E3],
|
|
87
|
+
d: Result[T4, E4],
|
|
88
|
+
e: Result[T5, E5],
|
|
89
|
+
f: Result[T6, E6],
|
|
90
|
+
g: Result[T7, E7],
|
|
91
|
+
/,
|
|
92
|
+
) -> Result[tuple[T1, T2, T3, T4, T5, T6, T7], Union[E1, E2, E3, E4, E5, E6, E7]]: ...
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
@overload
|
|
96
|
+
def collect(
|
|
97
|
+
a: Result[T1, E1],
|
|
98
|
+
b: Result[T2, E2],
|
|
99
|
+
c: Result[T3, E3],
|
|
100
|
+
d: Result[T4, E4],
|
|
101
|
+
e: Result[T5, E5],
|
|
102
|
+
f: Result[T6, E6],
|
|
103
|
+
g: Result[T7, E7],
|
|
104
|
+
h: Result[T8, E8],
|
|
105
|
+
/,
|
|
106
|
+
) -> Result[
|
|
107
|
+
tuple[T1, T2, T3, T4, T5, T6, T7, T8],
|
|
108
|
+
Union[E1, E2, E3, E4, E5, E6, E7, E8],
|
|
109
|
+
]: ...
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
@overload
|
|
113
|
+
def collect(
|
|
114
|
+
a: Result[T1, E1],
|
|
115
|
+
b: Result[T2, E2],
|
|
116
|
+
c: Result[T3, E3],
|
|
117
|
+
d: Result[T4, E4],
|
|
118
|
+
e: Result[T5, E5],
|
|
119
|
+
f: Result[T6, E6],
|
|
120
|
+
g: Result[T7, E7],
|
|
121
|
+
h: Result[T8, E8],
|
|
122
|
+
i: Result[T9, E9],
|
|
123
|
+
/,
|
|
124
|
+
) -> Result[
|
|
125
|
+
tuple[T1, T2, T3, T4, T5, T6, T7, T8, T9],
|
|
126
|
+
Union[E1, E2, E3, E4, E5, E6, E7, E8, E9],
|
|
127
|
+
]: ...
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
def collect(
|
|
131
|
+
initial: Result[Any, Any],
|
|
132
|
+
*others: Result[Any, Any],
|
|
133
|
+
) -> Result[tuple[Any, ...], Any]:
|
|
134
|
+
def _combine(
|
|
135
|
+
a: Result[tuple[Any, ...], Any],
|
|
136
|
+
b: Result[Any, Any],
|
|
137
|
+
) -> Result[tuple[Any, ...], Any]:
|
|
138
|
+
if is_err(a):
|
|
139
|
+
return Error(a.error)
|
|
140
|
+
elif is_err(b):
|
|
141
|
+
return Error(b.error)
|
|
142
|
+
else:
|
|
143
|
+
return Ok(((*a.value, b.value))) # type: ignore
|
|
144
|
+
|
|
145
|
+
return functools.reduce(_combine, [initial, *others], Ok(()))
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
def collect_all(iterable: Iterable[Result[T, E]]) -> Result[tuple[T, ...], E]:
|
|
149
|
+
def _combine(
|
|
150
|
+
a: Result[tuple[T, ...], E],
|
|
151
|
+
b: Result[T, E],
|
|
152
|
+
) -> Result[tuple[T, ...], E]:
|
|
153
|
+
if is_err(a):
|
|
154
|
+
return Error(a.error)
|
|
155
|
+
elif is_err(b):
|
|
156
|
+
return Error(b.error)
|
|
157
|
+
else:
|
|
158
|
+
return Ok(((*a.value, b.value))) # type: ignore
|
|
159
|
+
|
|
160
|
+
return functools.reduce(_combine, iterable, Ok(()))
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import TYPE_CHECKING, TypeVar
|
|
4
|
+
|
|
5
|
+
from stdlibx.result import Result, methods
|
|
6
|
+
|
|
7
|
+
if TYPE_CHECKING:
|
|
8
|
+
from stdlibx.option import Option
|
|
9
|
+
from stdlibx.result._types import Operation
|
|
10
|
+
|
|
11
|
+
T = TypeVar("T")
|
|
12
|
+
E = TypeVar("E")
|
|
13
|
+
U = TypeVar("U")
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def ok() -> Operation[Result[T, E], Option[T]]:
|
|
17
|
+
return methods.ok
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def err() -> Operation[Result[T, E], Option[E]]:
|
|
21
|
+
return methods.err
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def transpose() -> Operation[Result[Option[U], E], Option[Result[U, E]]]:
|
|
25
|
+
return methods.transpose
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
from stdlibx.result.methods.base import (
|
|
2
|
+
and_,
|
|
3
|
+
and_then,
|
|
4
|
+
expect,
|
|
5
|
+
expect_err,
|
|
6
|
+
flatten,
|
|
7
|
+
inspect,
|
|
8
|
+
inspect_err,
|
|
9
|
+
is_err_and,
|
|
10
|
+
is_ok_and,
|
|
11
|
+
map_,
|
|
12
|
+
map_err,
|
|
13
|
+
map_or,
|
|
14
|
+
map_or_else,
|
|
15
|
+
or_,
|
|
16
|
+
or_else,
|
|
17
|
+
unwrap,
|
|
18
|
+
unwrap_err,
|
|
19
|
+
unwrap_or,
|
|
20
|
+
unwrap_or_else,
|
|
21
|
+
unwrap_or_raise,
|
|
22
|
+
zipped,
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
__all__ = [
|
|
26
|
+
"and_",
|
|
27
|
+
"and_then",
|
|
28
|
+
"expect",
|
|
29
|
+
"expect_err",
|
|
30
|
+
"flatten",
|
|
31
|
+
"inspect",
|
|
32
|
+
"inspect_err",
|
|
33
|
+
"is_err_and",
|
|
34
|
+
"is_ok_and",
|
|
35
|
+
"map_",
|
|
36
|
+
"map_err",
|
|
37
|
+
"map_or",
|
|
38
|
+
"map_or_else",
|
|
39
|
+
"or_",
|
|
40
|
+
"or_else",
|
|
41
|
+
"unwrap",
|
|
42
|
+
"unwrap_err",
|
|
43
|
+
"unwrap_or",
|
|
44
|
+
"unwrap_or_else",
|
|
45
|
+
"unwrap_or_raise",
|
|
46
|
+
"zipped",
|
|
47
|
+
]
|
|
48
|
+
|
|
49
|
+
try:
|
|
50
|
+
from stdlibx.result.methods.option import err, ok, transpose
|
|
51
|
+
|
|
52
|
+
__all__ += ["err", "ok", "transpose"]
|
|
53
|
+
except ImportError:
|
|
54
|
+
pass
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Callable, TypeVar, Union
|
|
4
|
+
|
|
5
|
+
from stdlibx.result._errors import ResultExpectError, ResultUnwrapError
|
|
6
|
+
from stdlibx.result._result import Error, Ok, Result, is_err, is_ok
|
|
7
|
+
from typing_extensions import TypeVarTuple, Unpack
|
|
8
|
+
|
|
9
|
+
T = TypeVar("T")
|
|
10
|
+
E = TypeVar("E")
|
|
11
|
+
U = TypeVar("U")
|
|
12
|
+
F = TypeVar("F")
|
|
13
|
+
Ts = TypeVarTuple("Ts")
|
|
14
|
+
_AnyException = TypeVar("_AnyException", bound=Exception)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def is_ok_and(result: Result[T, E], func: Callable[[T], bool]) -> bool:
|
|
18
|
+
return is_ok(result) and func(result.value)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def is_err_and(result: Result[T, E], func: Callable[[E], bool]) -> bool:
|
|
22
|
+
return is_err(result) and func(result.error)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def map_(result: Result[T, E], func: Callable[[T], U]) -> Result[U, E]:
|
|
26
|
+
if is_ok(result):
|
|
27
|
+
return Ok(func(result.value))
|
|
28
|
+
return Error(result.error) # type: ignore
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def map_or(result: Result[T, E], default: U, func: Callable[[T], U]) -> U:
|
|
32
|
+
if is_ok(result):
|
|
33
|
+
return func(result.value)
|
|
34
|
+
return default
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def map_or_else(
|
|
38
|
+
result: Result[T, E], default: Callable[[E], U], func: Callable[[T], U]
|
|
39
|
+
) -> U:
|
|
40
|
+
if is_ok(result):
|
|
41
|
+
return func(result.value)
|
|
42
|
+
return default(result.error) # type: ignore
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def map_err(result: Result[T, E], func: Callable[[E], F]) -> Result[T, F]:
|
|
46
|
+
if is_err(result):
|
|
47
|
+
return Error(func(result.error))
|
|
48
|
+
return Ok(result.value) # type: ignore
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def inspect(result: Result[T, E], func: Callable[[T], None]) -> Result[T, E]:
|
|
52
|
+
if is_ok(result):
|
|
53
|
+
func(result.value)
|
|
54
|
+
return result
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def inspect_err(result: Result[T, E], func: Callable[[E], None]) -> Result[T, E]:
|
|
58
|
+
if is_err(result):
|
|
59
|
+
func(result.error)
|
|
60
|
+
return result
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def expect(result: Result[T, E], msg: str) -> T:
|
|
64
|
+
if is_ok(result):
|
|
65
|
+
return result.value
|
|
66
|
+
|
|
67
|
+
_msg = f"{msg}: {result.error}" # type: ignore
|
|
68
|
+
raise ResultExpectError(_msg)
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def unwrap(result: Result[T, E]) -> T:
|
|
72
|
+
if is_ok(result):
|
|
73
|
+
return result.value
|
|
74
|
+
|
|
75
|
+
_msg = f"{result.error}" # type: ignore
|
|
76
|
+
raise ResultUnwrapError(_msg)
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def expect_err(result: Result[T, E], msg: str) -> E:
|
|
80
|
+
if is_err(result):
|
|
81
|
+
return result.error
|
|
82
|
+
|
|
83
|
+
_msg = f"{msg}: {result.value}" # type: ignore
|
|
84
|
+
raise ResultExpectError(_msg)
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def unwrap_err(result: Result[T, E]) -> E:
|
|
88
|
+
if is_err(result):
|
|
89
|
+
return result.error
|
|
90
|
+
|
|
91
|
+
_msg = f"{result.value}" # type: ignore
|
|
92
|
+
raise ResultUnwrapError(_msg)
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def and_(result: Result[T, E], other: Result[U, F]) -> Result[U, Union[E, F]]:
|
|
96
|
+
if is_ok(result):
|
|
97
|
+
return other # type: ignore
|
|
98
|
+
return Error(result.error) # type: ignore
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def and_then(
|
|
102
|
+
result: Result[T, E], func: Callable[[T], Result[U, F]]
|
|
103
|
+
) -> Result[U, Union[E, F]]:
|
|
104
|
+
if is_ok(result):
|
|
105
|
+
return func(result.value) # type: ignore
|
|
106
|
+
return Error(result.error) # type: ignore
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def or_(result: Result[T, E], default: Result[T, F]) -> Result[T, F]:
|
|
110
|
+
if is_ok(result):
|
|
111
|
+
return Ok(result.value)
|
|
112
|
+
return default
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def or_else(result: Result[T, E], default: Callable[[E], Result[T, F]]) -> Result[T, F]:
|
|
116
|
+
if is_err(result):
|
|
117
|
+
return default(result.error)
|
|
118
|
+
return Ok(result.value) # type: ignore
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def unwrap_or(result: Result[T, E], default: T) -> T:
|
|
122
|
+
if is_ok(result):
|
|
123
|
+
return result.value
|
|
124
|
+
return default
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
def unwrap_or_else(result: Result[T, E], default: Callable[[E], T]) -> T:
|
|
128
|
+
if is_ok(result):
|
|
129
|
+
return result.value
|
|
130
|
+
return default(result.error) # type: ignore
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
def unwrap_or_raise(result: Result[T, _AnyException]) -> T:
|
|
134
|
+
if is_ok(result):
|
|
135
|
+
return result.value
|
|
136
|
+
raise result.error # type: ignore
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
def flatten(result: Result[Result[T, E], F]) -> Result[T, Union[E, F]]:
|
|
140
|
+
if is_ok(result):
|
|
141
|
+
return result.value # type: ignore
|
|
142
|
+
return Error(result.error) # type: ignore
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
def zipped(
|
|
146
|
+
result: Result[tuple[Unpack[Ts]], E], func: Callable[[Unpack[Ts]], Result[U, E]]
|
|
147
|
+
) -> Result[tuple[Unpack[Ts], U], E]:
|
|
148
|
+
if is_ok(result):
|
|
149
|
+
return map_(func(*result.value), lambda val: (*result.value, val))
|
|
150
|
+
return Error(result.error) # type: ignore
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import TypeVar
|
|
4
|
+
|
|
5
|
+
from stdlibx.option import Nothing, Option, Some, is_some
|
|
6
|
+
from stdlibx.result._result import Error, Ok, Result, is_err, is_ok
|
|
7
|
+
|
|
8
|
+
T = TypeVar("T")
|
|
9
|
+
E = TypeVar("E")
|
|
10
|
+
U = TypeVar("U")
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def ok(result: Result[T, E]) -> Option[T]:
|
|
14
|
+
if is_ok(result):
|
|
15
|
+
return Some(result.value)
|
|
16
|
+
return Nothing()
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def err(result: Result[T, E]) -> Option[E]:
|
|
20
|
+
if is_err(result):
|
|
21
|
+
return Some(result.error)
|
|
22
|
+
return Nothing()
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def transpose(result: Result[Option[U], E]) -> Option[Result[U, E]]:
|
|
26
|
+
if is_ok(result) and is_some(result.value):
|
|
27
|
+
return Some(Ok(result.value.value))
|
|
28
|
+
elif is_err(result):
|
|
29
|
+
return Some(Error(result.error))
|
|
30
|
+
else:
|
|
31
|
+
return Nothing()
|
|
File without changes
|