StructResult 0.6.2__tar.gz → 0.7.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.
- {structresult-0.6.2 → structresult-0.7.0}/PKG-INFO +1 -1
- {structresult-0.6.2 → structresult-0.7.0}/pyproject.toml +2 -3
- {structresult-0.6.2 → structresult-0.7.0}/src/StructResult/result.py +37 -41
- {structresult-0.6.2 → structresult-0.7.0}/src/StructResult.egg-info/PKG-INFO +1 -1
- {structresult-0.6.2 → structresult-0.7.0}/test/test_formatter.py +2 -4
- {structresult-0.6.2 → structresult-0.7.0}/test/test_result.py +5 -13
- {structresult-0.6.2 → structresult-0.7.0}/README.md +0 -0
- {structresult-0.6.2 → structresult-0.7.0}/setup.cfg +0 -0
- {structresult-0.6.2 → structresult-0.7.0}/src/StructResult/__init__.py +0 -0
- {structresult-0.6.2 → structresult-0.7.0}/src/StructResult/formatter.py +0 -0
- {structresult-0.6.2 → structresult-0.7.0}/src/StructResult/py.typed +0 -0
- {structresult-0.6.2 → structresult-0.7.0}/src/StructResult.egg-info/SOURCES.txt +0 -0
- {structresult-0.6.2 → structresult-0.7.0}/src/StructResult.egg-info/dependency_links.txt +0 -0
- {structresult-0.6.2 → structresult-0.7.0}/src/StructResult.egg-info/requires.txt +0 -0
- {structresult-0.6.2 → structresult-0.7.0}/src/StructResult.egg-info/top_level.txt +0 -0
|
@@ -9,7 +9,7 @@ where = ["src"]
|
|
|
9
9
|
|
|
10
10
|
[project]
|
|
11
11
|
name = "StructResult"
|
|
12
|
-
version = "0.
|
|
12
|
+
version = "0.7.0"
|
|
13
13
|
requires-python = ">= 3.12"
|
|
14
14
|
authors = [
|
|
15
15
|
{name="Serj Kotilevski", email="youserj@outlook.com"}
|
|
@@ -64,8 +64,7 @@ exclude = [
|
|
|
64
64
|
"venv",
|
|
65
65
|
]
|
|
66
66
|
include = [
|
|
67
|
-
"src
|
|
68
|
-
"examples/*/*.py",
|
|
67
|
+
"src/**/*.py",
|
|
69
68
|
"test/test_*.py"
|
|
70
69
|
]
|
|
71
70
|
|
|
@@ -1,28 +1,19 @@
|
|
|
1
1
|
from dataclasses import dataclass, field
|
|
2
|
-
from typing import Optional, Self,
|
|
2
|
+
from typing import Optional, Self, Protocol, Iterator, Any
|
|
3
3
|
|
|
4
4
|
|
|
5
|
-
class Result
|
|
6
|
-
|
|
7
|
-
err: Optional[ExceptionGroup]
|
|
8
|
-
msg: str = ""
|
|
5
|
+
class Result(Protocol):
|
|
6
|
+
msg: str
|
|
9
7
|
|
|
10
|
-
def
|
|
11
|
-
return iter((self.value, self.err))
|
|
8
|
+
def is_ok(self) -> bool: ...
|
|
12
9
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
return self.value
|
|
10
|
+
|
|
11
|
+
class ErrorPropagator(Result, Protocol):
|
|
12
|
+
err: Optional[ExceptionGroup]
|
|
17
13
|
|
|
18
14
|
def is_ok(self) -> bool:
|
|
19
15
|
return self.err is None
|
|
20
16
|
|
|
21
|
-
|
|
22
|
-
class ErrorGrouper(Protocol):
|
|
23
|
-
err: Optional[ExceptionGroup]
|
|
24
|
-
msg: str = ""
|
|
25
|
-
|
|
26
17
|
def append_err(self, e: Exception | ExceptionGroup) -> Self:
|
|
27
18
|
"""append except"""
|
|
28
19
|
if isinstance(e, ExceptionGroup):
|
|
@@ -41,61 +32,66 @@ class ErrorGrouper(Protocol):
|
|
|
41
32
|
self.err = ExceptionGroup(self.msg, (e, self.err))
|
|
42
33
|
return self
|
|
43
34
|
|
|
44
|
-
|
|
45
|
-
class ErrorPropagator(ErrorGrouper, Protocol):
|
|
46
|
-
def propagate_err[T](self, res: Result[T]) -> Optional[T]:
|
|
35
|
+
def propagate_err[T](self, res: "Collector[T]") -> Optional[T]:
|
|
47
36
|
"""Propagates (merges) the error from another Result into this one, returning its value"""
|
|
48
37
|
if res.err is not None:
|
|
49
38
|
self.append_err(res.err)
|
|
50
|
-
return res.value
|
|
39
|
+
return res.value if hasattr(res, "value") else None
|
|
51
40
|
|
|
52
41
|
|
|
53
|
-
class
|
|
54
|
-
|
|
42
|
+
class Collector[T](ErrorPropagator, Protocol):
|
|
43
|
+
value: T
|
|
44
|
+
|
|
45
|
+
def __iter__(self) -> Iterator[Any]:
|
|
46
|
+
return iter((self.value, self.err))
|
|
47
|
+
|
|
48
|
+
def unwrap(self) -> T:
|
|
49
|
+
if self.err:
|
|
50
|
+
raise self.err
|
|
51
|
+
return self.value
|
|
55
52
|
|
|
56
53
|
|
|
57
54
|
@dataclass(slots=True)
|
|
58
|
-
class Simple[T](
|
|
55
|
+
class Simple[T](Collector[Optional[T]], Result):
|
|
56
|
+
msg: str = ""
|
|
59
57
|
value: Optional[T] = field(default=None)
|
|
60
|
-
msg: str = field(default="")
|
|
61
58
|
err: Optional[ExceptionGroup] = field(init=False, default=None)
|
|
62
59
|
|
|
63
|
-
def
|
|
60
|
+
def set(self, res: "Simple[T]") -> Optional[T]:
|
|
64
61
|
"""set value and append errors"""
|
|
65
62
|
self.value = res.value
|
|
66
63
|
return self.propagate_err(res)
|
|
67
64
|
|
|
68
65
|
|
|
69
|
-
@dataclass(
|
|
70
|
-
class Null(Result
|
|
71
|
-
|
|
72
|
-
err: None = None
|
|
66
|
+
@dataclass(slots=True)
|
|
67
|
+
class Null(Result):
|
|
68
|
+
msg: str = ""
|
|
73
69
|
|
|
70
|
+
def is_ok(self) -> bool:
|
|
71
|
+
return True
|
|
74
72
|
|
|
75
|
-
NONE = Null()
|
|
76
|
-
"""None result"""
|
|
77
73
|
|
|
74
|
+
class Error(ErrorPropagator):
|
|
75
|
+
__slots__ = ("msg", "err")
|
|
78
76
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
msg: str = field(default="")
|
|
83
|
-
err: Optional[ExceptionGroup] = field(init=False, default=None)
|
|
77
|
+
def __init__(self, e: Exception, msg: str = "") -> None:
|
|
78
|
+
self.msg = msg
|
|
79
|
+
self.err = ExceptionGroup(self.msg, (e,))
|
|
84
80
|
|
|
85
81
|
|
|
86
82
|
@dataclass(slots=True)
|
|
87
|
-
class List[T](
|
|
88
|
-
msg: str =
|
|
89
|
-
value:
|
|
83
|
+
class List[T](Collector[list[Optional[T]]], Result):
|
|
84
|
+
msg: str = ""
|
|
85
|
+
value: list[Optional[T]] = field(init=False, default_factory=list)
|
|
90
86
|
err: Optional[ExceptionGroup] = field(init=False, default=None)
|
|
91
87
|
|
|
92
|
-
def append(self, res:
|
|
88
|
+
def append(self, res: Simple[T]) -> Optional[T]:
|
|
93
89
|
"""append value and errors"""
|
|
94
90
|
if self.value is None:
|
|
95
91
|
self.value = []
|
|
96
92
|
self.value.append(res.value)
|
|
97
93
|
return self.propagate_err(res)
|
|
98
94
|
|
|
99
|
-
def __add__(self, other:
|
|
95
|
+
def __add__(self, other: Simple[T]) -> Self:
|
|
100
96
|
self.append(other)
|
|
101
97
|
return self
|
|
@@ -17,8 +17,7 @@ class TestFormatEG(unittest.TestCase):
|
|
|
17
17
|
|
|
18
18
|
# Create test Result objects
|
|
19
19
|
self.simple_result = Simple[str](value="test")
|
|
20
|
-
self.error_result = Error(msg="error occurred")
|
|
21
|
-
self.error_result.append_err(self.simple_error)
|
|
20
|
+
self.error_result = Error(self.simple_error, msg="error occurred")
|
|
22
21
|
self.list_result = List[int]()
|
|
23
22
|
self.list_result.append(Simple[int](value=42))
|
|
24
23
|
self.list_result.append(Simple[int](value=None))
|
|
@@ -86,8 +85,7 @@ class TestFormatEG(unittest.TestCase):
|
|
|
86
85
|
self.assertTrue(result.endswith(expected))
|
|
87
86
|
|
|
88
87
|
def test_protocol_compatibility(self) -> None:
|
|
89
|
-
error_result = Error(msg="test")
|
|
90
|
-
error_result.append_err(self.complex_group)
|
|
88
|
+
error_result = Error(self.complex_group, msg="test")
|
|
91
89
|
|
|
92
90
|
self.assertIsInstance(error_result.err, BaseExceptionGroup)
|
|
93
91
|
if error_result.err is not None:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import unittest
|
|
2
2
|
from typing import Any
|
|
3
|
-
from src.StructResult.result import Simple,
|
|
3
|
+
from src.StructResult.result import Simple, Error, List, Null
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
class TestResultProtocols(unittest.TestCase):
|
|
@@ -28,20 +28,12 @@ class TestResultProtocols(unittest.TestCase):
|
|
|
28
28
|
self.assertEqual(list(res), [42, res.err])
|
|
29
29
|
|
|
30
30
|
def test_null(self) -> None:
|
|
31
|
-
self.
|
|
32
|
-
self.assertIsNone(NONE.err)
|
|
33
|
-
self.assertTrue(NONE.is_ok())
|
|
34
|
-
self.assertIsNone(NONE.unwrap())
|
|
35
|
-
self.assertEqual(list(NONE), [None, None])
|
|
31
|
+
self.assertTrue(Null().is_ok())
|
|
36
32
|
|
|
37
33
|
def test_error(self) -> None:
|
|
38
|
-
err = Error(msg="test")
|
|
39
|
-
err.append_err(self.exception1)
|
|
40
|
-
self.assertIsNone(err.value)
|
|
34
|
+
err = Error(self.exception1, msg="test")
|
|
41
35
|
self.assertIsNotNone(err.err)
|
|
42
36
|
self.assertFalse(err.is_ok())
|
|
43
|
-
with self.assertRaises(ExceptionGroup):
|
|
44
|
-
err.unwrap()
|
|
45
37
|
|
|
46
38
|
def test_list_append(self) -> None:
|
|
47
39
|
lst = List[int]()
|
|
@@ -136,12 +128,12 @@ class TestResultProtocols(unittest.TestCase):
|
|
|
136
128
|
res_err.append_err(self.exception1)
|
|
137
129
|
|
|
138
130
|
# Append OK result
|
|
139
|
-
simple.
|
|
131
|
+
simple.set(res_ok)
|
|
140
132
|
self.assertEqual(simple.value, 42)
|
|
141
133
|
self.assertIsNone(simple.err)
|
|
142
134
|
|
|
143
135
|
# Append error result
|
|
144
|
-
simple.
|
|
136
|
+
simple.set(res_err)
|
|
145
137
|
self.assertEqual(simple.value, 0)
|
|
146
138
|
self.assertIsNotNone(simple.err)
|
|
147
139
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|