PyDecisionGraph 0.1.1__py3-none-any.whl → 0.1.2__py3-none-any.whl
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.
Potentially problematic release.
This version of PyDecisionGraph might be problematic. Click here for more details.
- decision_graph/__init__.py +2 -2
- decision_graph/decision_tree/__init__.py +29 -17
- decision_graph/decision_tree/abc.py +65 -17
- decision_graph/decision_tree/collection.py +7 -13
- decision_graph/decision_tree/node.py +24 -10
- decision_graph/logic_group/__init__.py +22 -0
- decision_graph/logic_group/base.py +72 -0
- decision_graph/logic_group/pending_request.py +253 -0
- {pydecisiongraph-0.1.1.dist-info → pydecisiongraph-0.1.2.dist-info}/METADATA +1 -1
- pydecisiongraph-0.1.2.dist-info/RECORD +15 -0
- decision_graph/decision_tree/logic_group.py +0 -307
- pydecisiongraph-0.1.1.dist-info/RECORD +0 -13
- {pydecisiongraph-0.1.1.dist-info → pydecisiongraph-0.1.2.dist-info}/LICENSE +0 -0
- {pydecisiongraph-0.1.1.dist-info → pydecisiongraph-0.1.2.dist-info}/WHEEL +0 -0
- {pydecisiongraph-0.1.1.dist-info → pydecisiongraph-0.1.2.dist-info}/top_level.txt +0 -0
decision_graph/__init__.py
CHANGED
|
@@ -2,31 +2,43 @@ import logging
|
|
|
2
2
|
|
|
3
3
|
from .. import LOGGER
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
5
|
+
LOGGER = LOGGER.getChild("DecisionTree")
|
|
6
|
+
|
|
7
|
+
__all__ = [
|
|
8
|
+
'LOGGER', 'set_logger', 'activate_expression_model', 'activate_node_model',
|
|
9
|
+
'NodeError', 'TooManyChildren', 'TooFewChildren', 'NodeNotFountError', 'NodeValueError', 'EdgeValueError', 'ResolutionError', 'ExpressFalse', 'ContextsNotFound',
|
|
10
|
+
'LGM', 'LogicGroup', 'SkipContextsBlock', 'LogicExpression', 'ExpressionCollection', 'LogicNode', 'ActionNode', 'ELSE_CONDITION',
|
|
11
|
+
'NoAction', 'LongAction', 'ShortAction', 'RootLogicNode', 'ContextLogicExpression', 'AttrExpression', 'MathExpression', 'ComparisonExpression', 'LogicalExpression',
|
|
12
|
+
'LogicMapping', 'LogicGenerator'
|
|
13
|
+
]
|
|
14
|
+
|
|
15
|
+
from .exc import *
|
|
16
|
+
from .abc import *
|
|
17
|
+
from .node import *
|
|
18
|
+
from .collection import *
|
|
12
19
|
|
|
13
20
|
|
|
14
21
|
def set_logger(logger: logging.Logger):
|
|
15
22
|
global LOGGER
|
|
16
23
|
LOGGER = logger
|
|
17
24
|
|
|
18
|
-
|
|
19
|
-
abc.LOGGER = logger.getChild('TA')
|
|
25
|
+
abc.LOGGER = logger.getChild('abc')
|
|
20
26
|
|
|
21
27
|
|
|
22
|
-
|
|
28
|
+
def activate_expression_model():
|
|
29
|
+
import importlib
|
|
30
|
+
importlib.import_module('decision_graph.decision_tree.expression')
|
|
31
|
+
importlib.reload(collection)
|
|
32
|
+
collection.LogicMapping.AttrExpression = AttrExpression
|
|
33
|
+
collection.LogicGenerator.AttrExpression = AttrExpression
|
|
34
|
+
# importlib.reload(logic_group)
|
|
23
35
|
|
|
24
|
-
from .exc import *
|
|
25
|
-
from .abc import *
|
|
26
|
-
from .node import *
|
|
27
36
|
|
|
28
|
-
|
|
29
|
-
|
|
37
|
+
def activate_node_model():
|
|
38
|
+
import importlib
|
|
30
39
|
|
|
31
|
-
|
|
32
|
-
|
|
40
|
+
importlib.import_module('decision_graph.decision_tree.node')
|
|
41
|
+
importlib.reload(collection)
|
|
42
|
+
collection.LogicMapping.AttrExpression = AttrExpression
|
|
43
|
+
collection.LogicGenerator.AttrExpression = AttrExpression
|
|
44
|
+
# importlib.reload(logic_group)
|
|
@@ -11,6 +11,8 @@ from typing import Any, Self, final
|
|
|
11
11
|
from . import LOGGER
|
|
12
12
|
from .exc import TooFewChildren, TooManyChildren, EdgeValueError, NodeValueError, NodeNotFountError
|
|
13
13
|
|
|
14
|
+
LOGGER = LOGGER.getChild('abc')
|
|
15
|
+
|
|
14
16
|
__all__ = ['LGM', 'LogicGroup', 'SkipContextsBlock', 'LogicExpression', 'ExpressionCollection', 'LogicNode', 'ActionNode', 'ELSE_CONDITION']
|
|
15
17
|
|
|
16
18
|
|
|
@@ -46,9 +48,11 @@ class LogicGroupManager(metaclass=Singleton):
|
|
|
46
48
|
# Cursor to track the currently active LogicGroups
|
|
47
49
|
self._active_groups: list[LogicGroup] = []
|
|
48
50
|
self._active_nodes: list[LogicNode] = []
|
|
49
|
-
self.
|
|
50
|
-
self._pending_connection_nodes: list[ActionNode] = [] # for those
|
|
51
|
+
self._breakpoint_nodes: list[ActionNode] = [] # action nodes, usually NoAction() nodes, marked as an early-exit (breakpoint) of a logic group
|
|
52
|
+
self._pending_connection_nodes: list[ActionNode] = [] # for those breakpoint-nodes, they will be activated when the corresponding logic group is finalized.
|
|
53
|
+
self._shelved_state = [] # shelve state to support temporally initialize a separate node-graph
|
|
51
54
|
self.inspection_mode = False
|
|
55
|
+
self.vigilant_mode = False
|
|
52
56
|
|
|
53
57
|
def __call__(self, name: str, cls: type[LogicGroup], **kwargs) -> LogicGroup:
|
|
54
58
|
"""
|
|
@@ -95,7 +99,7 @@ class LogicGroupManager(metaclass=Singleton):
|
|
|
95
99
|
|
|
96
100
|
self._active_groups.pop(-1)
|
|
97
101
|
|
|
98
|
-
for node in self.
|
|
102
|
+
for node in self._breakpoint_nodes:
|
|
99
103
|
if getattr(node, 'break_from') is logic_group:
|
|
100
104
|
self._pending_connection_nodes.append(node)
|
|
101
105
|
|
|
@@ -129,6 +133,38 @@ class LogicGroupManager(metaclass=Singleton):
|
|
|
129
133
|
|
|
130
134
|
self._active_nodes.pop(-1)
|
|
131
135
|
|
|
136
|
+
def shelve(self):
|
|
137
|
+
shelved_state = dict(
|
|
138
|
+
active_nodes=self._active_nodes.copy(),
|
|
139
|
+
breakpoint_nodes=self._breakpoint_nodes.copy(),
|
|
140
|
+
pending_connection_nodes=self._pending_connection_nodes.copy()
|
|
141
|
+
)
|
|
142
|
+
|
|
143
|
+
self._active_nodes.clear()
|
|
144
|
+
self._breakpoint_nodes.clear()
|
|
145
|
+
self._pending_connection_nodes.clear()
|
|
146
|
+
|
|
147
|
+
self._shelved_state.append(shelved_state)
|
|
148
|
+
return shelved_state
|
|
149
|
+
|
|
150
|
+
def unshelve(self, reset_active: bool = True, reset_breakpoints: bool = True, reset_pending: bool = True):
|
|
151
|
+
shelved_state = self._shelved_state.pop(-1)
|
|
152
|
+
|
|
153
|
+
if reset_active:
|
|
154
|
+
self._active_nodes.clear()
|
|
155
|
+
|
|
156
|
+
if reset_breakpoints:
|
|
157
|
+
self._breakpoint_nodes.clear()
|
|
158
|
+
|
|
159
|
+
if reset_pending:
|
|
160
|
+
self._pending_connection_nodes.clear()
|
|
161
|
+
|
|
162
|
+
self._active_nodes[:0] = shelved_state['active_nodes']
|
|
163
|
+
self._breakpoint_nodes[:0] = shelved_state['breakpoint_nodes']
|
|
164
|
+
self._pending_connection_nodes[:0] = shelved_state['pending_connection_nodes']
|
|
165
|
+
|
|
166
|
+
return shelved_state
|
|
167
|
+
|
|
132
168
|
def clear(self):
|
|
133
169
|
"""
|
|
134
170
|
Clear the cache of LogicGroup instances and reset active groups.
|
|
@@ -242,12 +278,17 @@ class LogicGroup(object, metaclass=LogicGroupMeta):
|
|
|
242
278
|
if active_node is not None:
|
|
243
279
|
active_node: LogicNode
|
|
244
280
|
if not active_node.nodes:
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
281
|
+
if LGM.vigilant_mode:
|
|
282
|
+
raise TooFewChildren()
|
|
283
|
+
else:
|
|
284
|
+
LOGGER.warning('Must have at least one action node before breaking from logic group. A NoAction node will be automatically assigned.')
|
|
285
|
+
from .node import NoAction
|
|
286
|
+
NoAction()
|
|
287
|
+
|
|
288
|
+
last_node = active_node.last_leaf
|
|
289
|
+
assert isinstance(last_node, ActionNode), NodeValueError('An ActionNode is required before breaking a LogicGroup.')
|
|
290
|
+
last_node.break_from = scope
|
|
291
|
+
LGM._breakpoint_nodes.append(last_node)
|
|
251
292
|
return
|
|
252
293
|
|
|
253
294
|
raise scope.Break()
|
|
@@ -542,14 +583,14 @@ class LogicExpression(SkipContextsBlock):
|
|
|
542
583
|
|
|
543
584
|
|
|
544
585
|
class ExpressionCollection(LogicGroup):
|
|
545
|
-
def __init__(self, data: Any, name: str,
|
|
586
|
+
def __init__(self, data: Any, name: str, **kwargs):
|
|
546
587
|
if 'logic_group' not in kwargs:
|
|
547
588
|
logic_group = kwargs.get("logic_group")
|
|
548
589
|
else:
|
|
549
590
|
logic_group = LGM.active_logic_group
|
|
550
591
|
|
|
551
592
|
super().__init__(
|
|
552
|
-
name=
|
|
593
|
+
name=name if name is not None else f'{logic_group.name}.{self.__class__.__name__}',
|
|
553
594
|
parent=logic_group
|
|
554
595
|
)
|
|
555
596
|
|
|
@@ -1098,8 +1139,7 @@ class LogicNode(LogicExpression):
|
|
|
1098
1139
|
class ActionNode(LogicNode):
|
|
1099
1140
|
def __init__(
|
|
1100
1141
|
self,
|
|
1101
|
-
action:
|
|
1102
|
-
dtype: type = None,
|
|
1142
|
+
action: Callable[[], Any] | None = None,
|
|
1103
1143
|
repr: str = None,
|
|
1104
1144
|
auto_connect: bool = True
|
|
1105
1145
|
):
|
|
@@ -1108,10 +1148,10 @@ class ActionNode(LogicNode):
|
|
|
1108
1148
|
|
|
1109
1149
|
Args:
|
|
1110
1150
|
action (Union[Any, Callable[[], Any]]): The action to execute.
|
|
1111
|
-
dtype (type, optional): The expected type of the evaluated value (float, int, or bool).
|
|
1112
1151
|
repr (str, optional): A string representation of the expression.
|
|
1152
|
+
auto_connect: auto-connect to the current active decision graph.
|
|
1113
1153
|
"""
|
|
1114
|
-
super().__init__(expression=True,
|
|
1154
|
+
super().__init__(expression=True, repr=repr)
|
|
1115
1155
|
self.action = action
|
|
1116
1156
|
|
|
1117
1157
|
if auto_connect:
|
|
@@ -1123,6 +1163,14 @@ class ActionNode(LogicNode):
|
|
|
1123
1163
|
def _on_exit(self):
|
|
1124
1164
|
pass
|
|
1125
1165
|
|
|
1166
|
+
def _post_eval(self):
|
|
1167
|
+
"""
|
|
1168
|
+
override this method to perform clean up functions.
|
|
1169
|
+
"""
|
|
1170
|
+
|
|
1171
|
+
if self.action is not None:
|
|
1172
|
+
self.action()
|
|
1173
|
+
|
|
1126
1174
|
def eval_recursively(self, path=None):
|
|
1127
1175
|
"""
|
|
1128
1176
|
Evaluates the decision tree from this node based on the given state.
|
|
@@ -1134,10 +1182,10 @@ class ActionNode(LogicNode):
|
|
|
1134
1182
|
|
|
1135
1183
|
value = self.eval()
|
|
1136
1184
|
|
|
1137
|
-
|
|
1138
|
-
self.action()
|
|
1185
|
+
self._post_eval()
|
|
1139
1186
|
|
|
1140
1187
|
for condition, child in self.nodes.items():
|
|
1188
|
+
LOGGER.warning(f'{self.__class__.__name__} should not have any sub-nodes.')
|
|
1141
1189
|
if condition == value or condition is NO_CONDITION:
|
|
1142
1190
|
return child.eval_recursively(path=path)
|
|
1143
1191
|
|
|
@@ -3,16 +3,14 @@ from __future__ import annotations
|
|
|
3
3
|
from collections.abc import Mapping, Sequence
|
|
4
4
|
from typing import Any
|
|
5
5
|
|
|
6
|
-
from . import AttrExpression
|
|
6
|
+
from . import AttrExpression
|
|
7
7
|
from .abc import LogicGroup, ExpressionCollection
|
|
8
8
|
|
|
9
9
|
__all__ = ['LogicMapping', 'LogicGenerator']
|
|
10
10
|
|
|
11
11
|
|
|
12
12
|
class LogicMapping(ExpressionCollection):
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
def __init__(self, data: dict, name: str, repr: str = None, logic_group: LogicGroup = None):
|
|
13
|
+
def __init__(self, data: dict, name: str, logic_group: LogicGroup = None):
|
|
16
14
|
if data is None:
|
|
17
15
|
data = {}
|
|
18
16
|
|
|
@@ -22,7 +20,6 @@ class LogicMapping(ExpressionCollection):
|
|
|
22
20
|
super().__init__(
|
|
23
21
|
data=data,
|
|
24
22
|
name=name,
|
|
25
|
-
repr=repr,
|
|
26
23
|
logic_group=logic_group
|
|
27
24
|
)
|
|
28
25
|
|
|
@@ -33,10 +30,10 @@ class LogicMapping(ExpressionCollection):
|
|
|
33
30
|
return self.data.__len__()
|
|
34
31
|
|
|
35
32
|
def __getitem__(self, key: str):
|
|
36
|
-
return
|
|
33
|
+
return AttrExpression(attr=key, logic_group=self)
|
|
37
34
|
|
|
38
35
|
def __getattr__(self, key: str):
|
|
39
|
-
return
|
|
36
|
+
return AttrExpression(attr=key, logic_group=self)
|
|
40
37
|
|
|
41
38
|
def reset(self):
|
|
42
39
|
pass
|
|
@@ -52,9 +49,7 @@ class LogicMapping(ExpressionCollection):
|
|
|
52
49
|
|
|
53
50
|
|
|
54
51
|
class LogicGenerator(ExpressionCollection):
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
def __init__(self, data: list[Any], name: str, repr: str = None, logic_group: LogicGroup = None):
|
|
52
|
+
def __init__(self, data: list[Any], name: str, logic_group: LogicGroup = None):
|
|
58
53
|
if data is None:
|
|
59
54
|
data = []
|
|
60
55
|
|
|
@@ -64,7 +59,6 @@ class LogicGenerator(ExpressionCollection):
|
|
|
64
59
|
super().__init__(
|
|
65
60
|
data=data,
|
|
66
61
|
name=name,
|
|
67
|
-
repr=repr,
|
|
68
62
|
logic_group=logic_group
|
|
69
63
|
)
|
|
70
64
|
|
|
@@ -75,13 +69,13 @@ class LogicGenerator(ExpressionCollection):
|
|
|
75
69
|
# if isinstance(value, ContextLogicExpression):
|
|
76
70
|
# yield value
|
|
77
71
|
|
|
78
|
-
yield
|
|
72
|
+
yield AttrExpression(attr=index, logic_group=self)
|
|
79
73
|
|
|
80
74
|
def __len__(self) -> int:
|
|
81
75
|
return len(self.data)
|
|
82
76
|
|
|
83
77
|
def __getitem__(self, index: int):
|
|
84
|
-
return
|
|
78
|
+
return AttrExpression(attr=index, logic_group=self)
|
|
85
79
|
|
|
86
80
|
def append(self, value):
|
|
87
81
|
self.data.append(value)
|
|
@@ -14,11 +14,12 @@ __all__ = ['NoAction', 'LongAction', 'ShortAction', 'RootLogicNode', 'ContextLog
|
|
|
14
14
|
class NoAction(ActionNode):
|
|
15
15
|
def __init__(self, auto_connect: bool = True):
|
|
16
16
|
super().__init__(
|
|
17
|
-
action=None,
|
|
18
17
|
repr='<NoAction>',
|
|
19
18
|
auto_connect=auto_connect
|
|
20
19
|
)
|
|
21
20
|
|
|
21
|
+
self.sig = 0
|
|
22
|
+
|
|
22
23
|
def eval(self, enforce_dtype: bool = False) -> ActionNode:
|
|
23
24
|
return self
|
|
24
25
|
|
|
@@ -26,11 +27,12 @@ class NoAction(ActionNode):
|
|
|
26
27
|
class LongAction(ActionNode):
|
|
27
28
|
def __init__(self, sig: int = 1, auto_connect: bool = True):
|
|
28
29
|
super().__init__(
|
|
29
|
-
action=sig,
|
|
30
30
|
repr=f'<LongAction>(sig = {sig})',
|
|
31
31
|
auto_connect=auto_connect
|
|
32
32
|
)
|
|
33
33
|
|
|
34
|
+
self.sig = sig
|
|
35
|
+
|
|
34
36
|
def eval(self, enforce_dtype: bool = False) -> ActionNode:
|
|
35
37
|
return self
|
|
36
38
|
|
|
@@ -38,11 +40,12 @@ class LongAction(ActionNode):
|
|
|
38
40
|
class ShortAction(ActionNode):
|
|
39
41
|
def __init__(self, sig: int = -1, auto_connect: bool = True):
|
|
40
42
|
super().__init__(
|
|
41
|
-
action=sig,
|
|
42
43
|
repr=f'<ShortAction>(sig = {sig})',
|
|
43
44
|
auto_connect=auto_connect
|
|
44
45
|
)
|
|
45
46
|
|
|
47
|
+
self.sig = sig
|
|
48
|
+
|
|
46
49
|
def eval(self, enforce_dtype: bool = False) -> ActionNode:
|
|
47
50
|
return self
|
|
48
51
|
|
|
@@ -58,17 +61,28 @@ class RootLogicNode(LogicNode):
|
|
|
58
61
|
return True
|
|
59
62
|
|
|
60
63
|
def _on_enter(self):
|
|
61
|
-
|
|
62
|
-
LGM.inspection_mode = True
|
|
63
|
-
LGM._active_nodes.clear()
|
|
64
|
+
# pre-shelve call
|
|
64
65
|
LGM.enter_expression(node=self)
|
|
65
66
|
|
|
67
|
+
state = LGM.shelve()
|
|
68
|
+
|
|
69
|
+
state['inspection_mode'] = LGM.inspection_mode
|
|
70
|
+
|
|
71
|
+
LGM.inspection_mode = True
|
|
72
|
+
|
|
73
|
+
# post-shelve call
|
|
74
|
+
LGM._active_nodes.append(self)
|
|
75
|
+
|
|
66
76
|
def _on_exit(self):
|
|
77
|
+
# pre-unshelve call
|
|
78
|
+
# LGM.exit_expression(node=self)
|
|
79
|
+
|
|
80
|
+
state = LGM.unshelve()
|
|
81
|
+
|
|
82
|
+
# post-unshelve call
|
|
67
83
|
LGM.exit_expression(node=self)
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
else:
|
|
71
|
-
LGM.inspection_mode = False
|
|
84
|
+
|
|
85
|
+
LGM.inspection_mode = state['inspection_mode']
|
|
72
86
|
|
|
73
87
|
def append(self, expression: Self, edge_condition: Any = None):
|
|
74
88
|
if self.nodes:
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
|
|
3
|
+
from .. import LOGGER
|
|
4
|
+
|
|
5
|
+
LOGGER = LOGGER.getChild("LogicGroup")
|
|
6
|
+
|
|
7
|
+
__all__ = [
|
|
8
|
+
'SignalLogicGroup', 'InstantConfirmationLogicGroup',
|
|
9
|
+
'StateMapping', 'RequestAction', 'PendingRequest', 'RequestConfirmed', 'RequestDenied', 'RequestRegistered', 'DelayedConfirmationLogicGroup',
|
|
10
|
+
]
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def set_logger(logger: logging.Logger):
|
|
14
|
+
global LOGGER
|
|
15
|
+
LOGGER = logger
|
|
16
|
+
|
|
17
|
+
base.LOGGER = logger.getChild('base')
|
|
18
|
+
pending_request.LOGGER = logger.getChild('delayed')
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
from .base import *
|
|
22
|
+
from .pending_request import *
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Literal, Any, Self, overload
|
|
4
|
+
|
|
5
|
+
from . import LOGGER
|
|
6
|
+
from ..decision_tree import AttrExpression, LogicGroup, ActionNode, LGM, LongAction, ShortAction, NoAction
|
|
7
|
+
|
|
8
|
+
LOGGER = LOGGER.getChild('base')
|
|
9
|
+
|
|
10
|
+
__all__ = ['SignalLogicGroup', 'InstantConfirmationLogicGroup']
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class SignalLogicGroup(LogicGroup):
|
|
14
|
+
def __init__(self, name: str, parent: Self = None, contexts: dict[str, Any] = None):
|
|
15
|
+
super().__init__(name=name, parent=parent, contexts=contexts)
|
|
16
|
+
|
|
17
|
+
def get(self, attr: str, dtype: type = None, repr: str = None):
|
|
18
|
+
"""
|
|
19
|
+
Retrieve an attribute as a LogicExpression.
|
|
20
|
+
"""
|
|
21
|
+
return AttrExpression(attr=attr, logic_group=self, dtype=dtype, repr=repr)
|
|
22
|
+
|
|
23
|
+
def reset(self):
|
|
24
|
+
self.signal = 0
|
|
25
|
+
|
|
26
|
+
@property
|
|
27
|
+
def signal(self):
|
|
28
|
+
return self.contexts.get('signal', 0)
|
|
29
|
+
|
|
30
|
+
@signal.setter
|
|
31
|
+
def signal(self, value: int):
|
|
32
|
+
self.contexts['signal'] = value
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class InstantConfirmationLogicGroup(SignalLogicGroup):
|
|
36
|
+
def __init__(self, parent: SignalLogicGroup, name: str = None):
|
|
37
|
+
super().__init__(
|
|
38
|
+
name=f'{parent.name}.Instant' if name is None else name,
|
|
39
|
+
parent=parent
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
def reset(self):
|
|
43
|
+
pass
|
|
44
|
+
|
|
45
|
+
@overload
|
|
46
|
+
def confirm(self, sig: Literal[1]) -> LongAction:
|
|
47
|
+
...
|
|
48
|
+
|
|
49
|
+
@overload
|
|
50
|
+
def confirm(self, sig: Literal[-1]) -> ShortAction:
|
|
51
|
+
...
|
|
52
|
+
|
|
53
|
+
def confirm(self, sig: Literal[-1, 1]) -> ActionNode:
|
|
54
|
+
self.signal = sig
|
|
55
|
+
|
|
56
|
+
if sig > 0:
|
|
57
|
+
return LongAction(sig=sig)
|
|
58
|
+
elif sig < 0:
|
|
59
|
+
return ShortAction(sig=sig)
|
|
60
|
+
|
|
61
|
+
if not LGM.inspection_mode:
|
|
62
|
+
LOGGER.warning(f'{self} received a confirmation of {sig=}! Which is not expected.')
|
|
63
|
+
|
|
64
|
+
return NoAction()
|
|
65
|
+
|
|
66
|
+
@property
|
|
67
|
+
def signal(self):
|
|
68
|
+
return self.parent.signal
|
|
69
|
+
|
|
70
|
+
@signal.setter
|
|
71
|
+
def signal(self, value: int):
|
|
72
|
+
self.parent.signal = value
|
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import enum
|
|
4
|
+
import time
|
|
5
|
+
import uuid
|
|
6
|
+
from collections.abc import Mapping
|
|
7
|
+
from typing import Literal, Self, TypedDict
|
|
8
|
+
|
|
9
|
+
from . import LOGGER
|
|
10
|
+
from .base import SignalLogicGroup
|
|
11
|
+
from ..decision_tree import ActionNode, LogicMapping, LogicGroup, NodeValueError, LongAction, ShortAction, LGM, NoAction
|
|
12
|
+
|
|
13
|
+
LOGGER = LOGGER.getChild('request')
|
|
14
|
+
|
|
15
|
+
__all__ = ['RequestAction', 'PendingRequest', 'RequestConfirmed', 'RequestDenied', 'RequestRegistered', 'DelayedConfirmationLogicGroup']
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class StateMapping(TypedDict):
|
|
19
|
+
timestamp: float
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class RequestAction(enum.StrEnum):
|
|
23
|
+
open = enum.auto()
|
|
24
|
+
unwind = enum.auto()
|
|
25
|
+
idle = enum.auto()
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class PendingRequest(dict):
|
|
29
|
+
|
|
30
|
+
def __init__(
|
|
31
|
+
self,
|
|
32
|
+
name: str,
|
|
33
|
+
timestamp: float,
|
|
34
|
+
sig: Literal[-1, 1] | int,
|
|
35
|
+
action: str,
|
|
36
|
+
timeout: float,
|
|
37
|
+
logic_group: LogicGroup = None,
|
|
38
|
+
uid: uuid.UUID = None,
|
|
39
|
+
**kwargs
|
|
40
|
+
):
|
|
41
|
+
super().__init__(
|
|
42
|
+
name=name,
|
|
43
|
+
timestamp=timestamp,
|
|
44
|
+
sig=sig,
|
|
45
|
+
timeout=timeout,
|
|
46
|
+
action=RequestAction(action),
|
|
47
|
+
uid=uuid.uuid4() if uid is None else uid,
|
|
48
|
+
**kwargs
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
self.logic_group = logic_group
|
|
52
|
+
|
|
53
|
+
def reset(self) -> PendingRequest:
|
|
54
|
+
self.update(
|
|
55
|
+
name='DummyRequest',
|
|
56
|
+
timestamp=0,
|
|
57
|
+
sig=0,
|
|
58
|
+
action=RequestAction.idle,
|
|
59
|
+
timeout=0,
|
|
60
|
+
uid=uuid.UUID(int=0)
|
|
61
|
+
)
|
|
62
|
+
return self
|
|
63
|
+
|
|
64
|
+
@classmethod
|
|
65
|
+
def empty(cls) -> PendingRequest:
|
|
66
|
+
return PendingRequest(
|
|
67
|
+
name='DummyRequest',
|
|
68
|
+
timestamp=0,
|
|
69
|
+
sig=0,
|
|
70
|
+
action=RequestAction.idle,
|
|
71
|
+
timeout=0,
|
|
72
|
+
uid=uuid.UUID(int=0)
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
def __bool__(self):
|
|
76
|
+
if not self.sig:
|
|
77
|
+
return False
|
|
78
|
+
return True
|
|
79
|
+
|
|
80
|
+
@property
|
|
81
|
+
def name(self) -> str:
|
|
82
|
+
return self['name']
|
|
83
|
+
|
|
84
|
+
@property
|
|
85
|
+
def timestamp(self) -> float:
|
|
86
|
+
return self['timestamp']
|
|
87
|
+
|
|
88
|
+
@property
|
|
89
|
+
def sig(self) -> int:
|
|
90
|
+
return self['sig']
|
|
91
|
+
|
|
92
|
+
@property
|
|
93
|
+
def timeout(self) -> float:
|
|
94
|
+
return self['timeout']
|
|
95
|
+
|
|
96
|
+
@property
|
|
97
|
+
def action(self) -> RequestAction:
|
|
98
|
+
return self['action']
|
|
99
|
+
|
|
100
|
+
@property
|
|
101
|
+
def uid(self) -> uuid.UUID:
|
|
102
|
+
return self['uid']
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
class RequestConfirmed(ActionNode):
|
|
106
|
+
def __init__(self, sig: Literal[-1, 1], req: PendingRequest, auto_connect: bool = True):
|
|
107
|
+
super().__init__(
|
|
108
|
+
repr=f'<Pending Request Confirmed {sig=}>',
|
|
109
|
+
auto_connect=auto_connect
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
self.sig = sig
|
|
113
|
+
self.req = req
|
|
114
|
+
|
|
115
|
+
def eval(self, enforce_dtype: bool = False) -> ActionNode:
|
|
116
|
+
sig = self.sig
|
|
117
|
+
|
|
118
|
+
if sig > 0:
|
|
119
|
+
return LongAction(sig=sig, auto_connect=False)
|
|
120
|
+
elif sig < 0:
|
|
121
|
+
return ShortAction(sig=sig, auto_connect=False)
|
|
122
|
+
|
|
123
|
+
if not LGM.inspection_mode:
|
|
124
|
+
LOGGER.warning(f'{self} received a confirmation of {sig=}! Which is not expected.')
|
|
125
|
+
|
|
126
|
+
return NoAction(auto_connect=False)
|
|
127
|
+
|
|
128
|
+
def _post_eval(self) -> Self:
|
|
129
|
+
self.req.reset()
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
class RequestDenied(ActionNode):
|
|
133
|
+
def __init__(self, req: PendingRequest, auto_connect: bool = True):
|
|
134
|
+
super().__init__(
|
|
135
|
+
repr='<Pending Request Denied>',
|
|
136
|
+
auto_connect=auto_connect
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
self.req = req
|
|
140
|
+
|
|
141
|
+
def eval(self, enforce_dtype: bool = False) -> ActionNode:
|
|
142
|
+
return NoAction(auto_connect=False)
|
|
143
|
+
|
|
144
|
+
def _post_eval(self) -> Self:
|
|
145
|
+
self.req.reset()
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
class RequestRegistered(ActionNode):
|
|
149
|
+
def __init__(self, sig: Literal[-1, 1], req: PendingRequest, state: StateMapping | Mapping | LogicMapping = None, action: RequestAction = RequestAction.open, timeout: float = float('inf'), auto_connect: bool = True):
|
|
150
|
+
super().__init__(
|
|
151
|
+
action=self._registered,
|
|
152
|
+
repr=f'<Pending Request Registered {sig=}>',
|
|
153
|
+
auto_connect=auto_connect
|
|
154
|
+
)
|
|
155
|
+
|
|
156
|
+
self.state = state
|
|
157
|
+
self.req = req
|
|
158
|
+
|
|
159
|
+
self.sig = sig
|
|
160
|
+
self.action = action
|
|
161
|
+
self.timeout = timeout
|
|
162
|
+
|
|
163
|
+
def eval(self, enforce_dtype: bool = False) -> ActionNode:
|
|
164
|
+
return NoAction(auto_connect=False)
|
|
165
|
+
|
|
166
|
+
def _registered(self) -> Self:
|
|
167
|
+
sig = self.sig
|
|
168
|
+
timestamp = time.time() if self.state is None else self.state['timestamp']
|
|
169
|
+
action = self.action
|
|
170
|
+
timeout = self.timeout
|
|
171
|
+
uid = uuid.uuid4()
|
|
172
|
+
|
|
173
|
+
if self.sig > 0:
|
|
174
|
+
name = 'state.long'
|
|
175
|
+
elif self.sig < 0:
|
|
176
|
+
name = 'state.short'
|
|
177
|
+
else:
|
|
178
|
+
raise NodeValueError('Signal Must not be zero.')
|
|
179
|
+
|
|
180
|
+
self.req.update(
|
|
181
|
+
name=name,
|
|
182
|
+
timestamp=timestamp,
|
|
183
|
+
sig=sig,
|
|
184
|
+
timeout=timeout,
|
|
185
|
+
action=action,
|
|
186
|
+
uid=uid
|
|
187
|
+
)
|
|
188
|
+
|
|
189
|
+
return self
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
class DelayedConfirmationLogicGroup(SignalLogicGroup):
|
|
193
|
+
def __init__(self, parent: SignalLogicGroup, name: str = None):
|
|
194
|
+
super().__init__(
|
|
195
|
+
name=f'{parent.name}.Delayed' if name is None else name,
|
|
196
|
+
parent=parent
|
|
197
|
+
)
|
|
198
|
+
|
|
199
|
+
self.req = self.contexts['pending_request'] = PendingRequest.empty()
|
|
200
|
+
|
|
201
|
+
def register(self, sig: Literal[1, -1], state: StateMapping | Mapping | LogicMapping = None, timeout: float = float('inf'), action: RequestAction | str = RequestAction.open) -> RequestRegistered:
|
|
202
|
+
action_register = RequestRegistered(
|
|
203
|
+
sig=sig,
|
|
204
|
+
req=self.req,
|
|
205
|
+
state=state,
|
|
206
|
+
action=RequestAction(action),
|
|
207
|
+
timeout=timeout
|
|
208
|
+
)
|
|
209
|
+
|
|
210
|
+
return action_register
|
|
211
|
+
|
|
212
|
+
def confirm(self, sig: Literal[1, -1]) -> RequestConfirmed:
|
|
213
|
+
action_confirm = RequestConfirmed(req=self.req, sig=sig)
|
|
214
|
+
return action_confirm
|
|
215
|
+
|
|
216
|
+
def deny(self) -> RequestDenied:
|
|
217
|
+
action_deny = RequestDenied(req=self.req)
|
|
218
|
+
return action_deny
|
|
219
|
+
|
|
220
|
+
def reset(self):
|
|
221
|
+
self.pending_request.reset()
|
|
222
|
+
super().reset()
|
|
223
|
+
|
|
224
|
+
@property
|
|
225
|
+
def action(self) -> RequestAction:
|
|
226
|
+
return self.pending_request.action
|
|
227
|
+
|
|
228
|
+
@property
|
|
229
|
+
def pending_request(self) -> LogicMapping:
|
|
230
|
+
req = self.req
|
|
231
|
+
|
|
232
|
+
m = LogicMapping(
|
|
233
|
+
data=req,
|
|
234
|
+
name=f'{self.name}.PendingRequest',
|
|
235
|
+
logic_group=self
|
|
236
|
+
)
|
|
237
|
+
|
|
238
|
+
return m
|
|
239
|
+
|
|
240
|
+
@pending_request.setter
|
|
241
|
+
def pending_request(self, value: PendingRequest):
|
|
242
|
+
LOGGER.warning('Assigning pending request will break the reference of previous generated decision graph. Use with caution.')
|
|
243
|
+
assert isinstance(value, PendingRequest)
|
|
244
|
+
self.req = self.contexts['pending_request'] = value
|
|
245
|
+
|
|
246
|
+
@property
|
|
247
|
+
def signal(self):
|
|
248
|
+
return self.parent.signal
|
|
249
|
+
|
|
250
|
+
@signal.setter
|
|
251
|
+
def signal(self, value: Literal[-1, 0, 1]):
|
|
252
|
+
assert isinstance(value, (int, float))
|
|
253
|
+
self.parent.signal = value
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
decision_graph/__init__.py,sha256=4QpoJ4PAJKXqLFITUOq55uOILaN60NWWz6q-FIBhYH4,386
|
|
2
|
+
decision_graph/decision_tree/__init__.py,sha256=S1UVgQ_wj1QQ9SkVkVvVOLKA_kjulvuo56EcBIt6spM,1512
|
|
3
|
+
decision_graph/decision_tree/abc.py,sha256=28tGBgXicJ802oLCPQm0Gvcm54mB1pMpbHimnt2L1MU,42114
|
|
4
|
+
decision_graph/decision_tree/collection.py,sha256=PLb58A_SS7vLRJ0l-T1OaZFHYhAHjdwij68uP_HpL70,2242
|
|
5
|
+
decision_graph/decision_tree/exc.py,sha256=THgIIP8S2PyJ9HIyUbNRhKT1umHfmf3Nh4rYrV8ywXU,646
|
|
6
|
+
decision_graph/decision_tree/expression.py,sha256=_bd1U2tjHnCydoC1Ya6RwTasRbKweMzUsghXsDe4ZpA,16777
|
|
7
|
+
decision_graph/decision_tree/node.py,sha256=x69Fa3izFQZRU_4urwYGorTR_eNAOr2IbKU7P5eeCnI,8721
|
|
8
|
+
decision_graph/logic_group/__init__.py,sha256=7lnQfCbVdgP3DtsCwFJ3Ht1Ig9LKONgdX2zvHT3gT1M,528
|
|
9
|
+
decision_graph/logic_group/base.py,sha256=F3eUO5nE4mB11f_KiSMpiYGFUAf947-2ESxbzskHT2U,1942
|
|
10
|
+
decision_graph/logic_group/pending_request.py,sha256=0Caip4FGFqdqiw1VaRlASDJv57ExQnAvlq3PQB1NCr8,6888
|
|
11
|
+
pydecisiongraph-0.1.2.dist-info/LICENSE,sha256=HyVuytGSiAUQ6ErWBHTqt1iSGHhLmlC8fO7jTCuR8dU,16725
|
|
12
|
+
pydecisiongraph-0.1.2.dist-info/METADATA,sha256=pjalVP0bT4Z1Rkx9Qki7f-SED8NxedVl27Qfhz1hWNU,5456
|
|
13
|
+
pydecisiongraph-0.1.2.dist-info/WHEEL,sha256=jB7zZ3N9hIM9adW7qlTAyycLYW9npaWKLRzaoVcLKcM,91
|
|
14
|
+
pydecisiongraph-0.1.2.dist-info/top_level.txt,sha256=3_p81U9qj9sTh1K6a1ZE-JNv7LKHaCeavuzci28VjFk,15
|
|
15
|
+
pydecisiongraph-0.1.2.dist-info/RECORD,,
|
|
@@ -1,307 +0,0 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
import enum
|
|
4
|
-
import uuid
|
|
5
|
-
from typing import Literal, Any, Self
|
|
6
|
-
|
|
7
|
-
from . import AttrExpression, LogicMapping
|
|
8
|
-
from .abc import LogicGroup, SkipContextsBlock
|
|
9
|
-
|
|
10
|
-
__all__ = ['SignalLogicGroup', 'InstantConfirmationLogicGroup', 'RequestAction', 'PendingRequest', 'DelayedConfirmationLogicGroup', 'RacingConfirmationLogicGroup', 'BarrierConfirmationLogicGroup']
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
class SignalLogicGroup(LogicGroup):
|
|
14
|
-
def __init__(self, name: str, parent: Self = None, contexts: dict[str, Any] = None):
|
|
15
|
-
super().__init__(name=name, parent=parent, contexts=contexts)
|
|
16
|
-
|
|
17
|
-
def get(self, attr: str, dtype: type = None, repr: str = None):
|
|
18
|
-
"""
|
|
19
|
-
Retrieve an attribute as a LogicExpression.
|
|
20
|
-
"""
|
|
21
|
-
return AttrExpression(attr=attr, logic_group=self, dtype=dtype, repr=repr)
|
|
22
|
-
|
|
23
|
-
def reset(self):
|
|
24
|
-
self.signal = 0
|
|
25
|
-
|
|
26
|
-
@property
|
|
27
|
-
def signal(self):
|
|
28
|
-
return self.contexts.get('signal', 0)
|
|
29
|
-
|
|
30
|
-
@signal.setter
|
|
31
|
-
def signal(self, value: int):
|
|
32
|
-
self.contexts['signal'] = value
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
class InstantConfirmationLogicGroup(SignalLogicGroup):
|
|
36
|
-
def __init__(self, parent: SignalLogicGroup, name: str = None):
|
|
37
|
-
super().__init__(
|
|
38
|
-
name=f'{parent.name}.Instant' if name is None else name,
|
|
39
|
-
parent=parent
|
|
40
|
-
)
|
|
41
|
-
|
|
42
|
-
def reset(self):
|
|
43
|
-
pass
|
|
44
|
-
|
|
45
|
-
def confirm(self, sig: Literal[-1, 1]):
|
|
46
|
-
self.signal = sig
|
|
47
|
-
return
|
|
48
|
-
|
|
49
|
-
@property
|
|
50
|
-
def signal(self):
|
|
51
|
-
return self.parent.signal
|
|
52
|
-
|
|
53
|
-
@signal.setter
|
|
54
|
-
def signal(self, value: int):
|
|
55
|
-
self.parent.signal = value
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
class RequestAction(enum.StrEnum):
|
|
59
|
-
open = enum.auto()
|
|
60
|
-
unwind = enum.auto()
|
|
61
|
-
idle = enum.auto()
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
class PendingRequest(dict):
|
|
65
|
-
class Skip(Exception):
|
|
66
|
-
pass
|
|
67
|
-
|
|
68
|
-
def __init__(
|
|
69
|
-
self,
|
|
70
|
-
name: str | RequestAction,
|
|
71
|
-
timestamp: float,
|
|
72
|
-
sig: Literal[-1, 1] | int,
|
|
73
|
-
action: str,
|
|
74
|
-
timeout: float,
|
|
75
|
-
logic_group: LogicGroup = None,
|
|
76
|
-
uid: uuid.UUID = None,
|
|
77
|
-
**kwargs
|
|
78
|
-
):
|
|
79
|
-
super().__init__(
|
|
80
|
-
name=name,
|
|
81
|
-
timestamp=timestamp,
|
|
82
|
-
sig=sig,
|
|
83
|
-
timeout=timeout,
|
|
84
|
-
action=RequestAction(action),
|
|
85
|
-
uid=uuid.uuid4() if uid is None else uid,
|
|
86
|
-
**kwargs
|
|
87
|
-
)
|
|
88
|
-
|
|
89
|
-
self.logic_group = logic_group
|
|
90
|
-
|
|
91
|
-
@classmethod
|
|
92
|
-
def empty(cls) -> PendingRequest:
|
|
93
|
-
return PendingRequest(
|
|
94
|
-
name='DummyRequest',
|
|
95
|
-
timestamp=0,
|
|
96
|
-
sig=0,
|
|
97
|
-
action=RequestAction.idle,
|
|
98
|
-
timeout=0,
|
|
99
|
-
uid=uuid.UUID(int=0)
|
|
100
|
-
)
|
|
101
|
-
|
|
102
|
-
def __bool__(self):
|
|
103
|
-
if not self.sig:
|
|
104
|
-
return False
|
|
105
|
-
return True
|
|
106
|
-
|
|
107
|
-
@property
|
|
108
|
-
def name(self) -> str:
|
|
109
|
-
return self['name']
|
|
110
|
-
|
|
111
|
-
@property
|
|
112
|
-
def timestamp(self) -> float:
|
|
113
|
-
return self['timestamp']
|
|
114
|
-
|
|
115
|
-
@property
|
|
116
|
-
def sig(self) -> int:
|
|
117
|
-
return self['sig']
|
|
118
|
-
|
|
119
|
-
@property
|
|
120
|
-
def timeout(self) -> float:
|
|
121
|
-
return self['timeout']
|
|
122
|
-
|
|
123
|
-
@property
|
|
124
|
-
def action(self) -> RequestAction:
|
|
125
|
-
return self['action']
|
|
126
|
-
|
|
127
|
-
@property
|
|
128
|
-
def uid(self) -> uuid.UUID:
|
|
129
|
-
return self['uid']
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
class DelayedConfirmationLogicGroup(SignalLogicGroup):
|
|
133
|
-
def __init__(self, parent: SignalLogicGroup, name: str = None):
|
|
134
|
-
super().__init__(
|
|
135
|
-
name=f'{parent.name}.Delayed' if name is None else name,
|
|
136
|
-
parent=parent
|
|
137
|
-
)
|
|
138
|
-
|
|
139
|
-
def register(self, name: str, timestamp: float, sig: Literal[1, -1], timeout: float | None, action: Literal['open', 'unwind'] = 'open', uid: uuid.UUID = None, **kwargs):
|
|
140
|
-
req = self.pending_request = PendingRequest(
|
|
141
|
-
name=name,
|
|
142
|
-
logic_group=self,
|
|
143
|
-
timestamp=timestamp,
|
|
144
|
-
sig=sig,
|
|
145
|
-
timeout=timeout,
|
|
146
|
-
action=action,
|
|
147
|
-
uid=uid,
|
|
148
|
-
**kwargs
|
|
149
|
-
)
|
|
150
|
-
|
|
151
|
-
return req
|
|
152
|
-
|
|
153
|
-
def confirm(self):
|
|
154
|
-
req = self.contexts.get('pending_request')
|
|
155
|
-
sig = 0 if req is None else req.sig
|
|
156
|
-
self.reset()
|
|
157
|
-
self.signal = sig
|
|
158
|
-
return sig
|
|
159
|
-
|
|
160
|
-
def deny(self):
|
|
161
|
-
# denying all the pending request
|
|
162
|
-
self.reset()
|
|
163
|
-
return 0
|
|
164
|
-
|
|
165
|
-
def reset(self):
|
|
166
|
-
# self.pending_request = PendingRequest.empty()
|
|
167
|
-
self.contexts.pop('pending_request', None)
|
|
168
|
-
super().reset()
|
|
169
|
-
|
|
170
|
-
@property
|
|
171
|
-
def action(self) -> RequestAction:
|
|
172
|
-
if 'pending_request' in self.contexts:
|
|
173
|
-
return self.pending_request.action
|
|
174
|
-
|
|
175
|
-
return RequestAction.idle
|
|
176
|
-
|
|
177
|
-
@property
|
|
178
|
-
def pending_request(self) -> LogicMapping | SkipContextsBlock:
|
|
179
|
-
|
|
180
|
-
if (req := self.contexts.get('pending_request')) is None:
|
|
181
|
-
return SkipContextsBlock(True)
|
|
182
|
-
|
|
183
|
-
m = LogicMapping(
|
|
184
|
-
data=req,
|
|
185
|
-
name=f'{self.name}.PendingRequest.{req.uid.hex}',
|
|
186
|
-
logic_group=self
|
|
187
|
-
)
|
|
188
|
-
|
|
189
|
-
return m
|
|
190
|
-
|
|
191
|
-
@pending_request.setter
|
|
192
|
-
def pending_request(self, value: PendingRequest):
|
|
193
|
-
assert isinstance(value, PendingRequest)
|
|
194
|
-
self.contexts['pending_request'] = value
|
|
195
|
-
|
|
196
|
-
@property
|
|
197
|
-
def signal(self):
|
|
198
|
-
return self.parent.signal
|
|
199
|
-
|
|
200
|
-
@signal.setter
|
|
201
|
-
def signal(self, value: Literal[-1, 0, 1]):
|
|
202
|
-
assert isinstance(value, (int, float))
|
|
203
|
-
self.parent.signal = value
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
class RacingConfirmationLogicGroup(DelayedConfirmationLogicGroup):
|
|
207
|
-
|
|
208
|
-
def __init__(self, parent: SignalLogicGroup, name: str = None):
|
|
209
|
-
super().__init__(
|
|
210
|
-
name=f'{parent.name}.Racing' if name is None else name,
|
|
211
|
-
parent=parent
|
|
212
|
-
)
|
|
213
|
-
|
|
214
|
-
def __getitem__(self, uid: uuid.UUID | str | bytes | int) -> PendingRequest:
|
|
215
|
-
if not (request_pool := self.pending_request):
|
|
216
|
-
raise KeyError(f'uid {uid} not found!')
|
|
217
|
-
|
|
218
|
-
match uid:
|
|
219
|
-
case uuid.UUID():
|
|
220
|
-
for _pending_request in request_pool:
|
|
221
|
-
if _pending_request.uid == uid:
|
|
222
|
-
return _pending_request
|
|
223
|
-
raise KeyError(f'uid {uid} not found!')
|
|
224
|
-
case str():
|
|
225
|
-
for _pending_request in request_pool:
|
|
226
|
-
if _pending_request.uid.hex == uid:
|
|
227
|
-
return _pending_request
|
|
228
|
-
raise KeyError(f'uid {uid} not found!')
|
|
229
|
-
case bytes():
|
|
230
|
-
for _pending_request in request_pool:
|
|
231
|
-
if _pending_request.uid.bytes == uid:
|
|
232
|
-
return _pending_request
|
|
233
|
-
raise KeyError(f'uid {uid} not found!')
|
|
234
|
-
case int():
|
|
235
|
-
return request_pool[uid]
|
|
236
|
-
case _:
|
|
237
|
-
raise TypeError(f'Invalid uid {uid}! Expected UUID or bytes or str!')
|
|
238
|
-
|
|
239
|
-
def register(self, name: str, timestamp: float, sig: Literal[1, -1], timeout: float, action: Literal['open', 'unwind'] = 'open', uid: uuid.UUID = None, **kwargs):
|
|
240
|
-
self.pending_request.append(
|
|
241
|
-
PendingRequest(
|
|
242
|
-
name=name,
|
|
243
|
-
timestamp=timestamp,
|
|
244
|
-
sig=sig,
|
|
245
|
-
timeout=timeout,
|
|
246
|
-
action=action,
|
|
247
|
-
uid=uid,
|
|
248
|
-
**kwargs
|
|
249
|
-
)
|
|
250
|
-
)
|
|
251
|
-
|
|
252
|
-
def confirm(self, pending_request: PendingRequest = None, uid: uuid.UUID = None):
|
|
253
|
-
if pending_request is None and uid is None:
|
|
254
|
-
assert len(self.pending_request) == 1, ValueError('Multiple pending requests found! Must assign uid or pending_request instance!')
|
|
255
|
-
pending_request = self.pending_request[0]
|
|
256
|
-
elif pending_request is None:
|
|
257
|
-
pending_request = self.__getitem__(uid=uid)
|
|
258
|
-
|
|
259
|
-
sig = pending_request.sig
|
|
260
|
-
self.reset()
|
|
261
|
-
self.signal = sig
|
|
262
|
-
return sig
|
|
263
|
-
|
|
264
|
-
def deny(self, pending_request: PendingRequest = None, uid: uuid.UUID = None):
|
|
265
|
-
# denying all the pending request
|
|
266
|
-
if pending_request is None and uid is None:
|
|
267
|
-
self.pending_request.clear()
|
|
268
|
-
self.signal = 0
|
|
269
|
-
return
|
|
270
|
-
|
|
271
|
-
if pending_request is not None:
|
|
272
|
-
self.pending_request.remove(pending_request)
|
|
273
|
-
self.signal = 0
|
|
274
|
-
|
|
275
|
-
if uid is not None:
|
|
276
|
-
pending_request = self.__getitem__(uid=uid)
|
|
277
|
-
self.pending_request.remove(pending_request)
|
|
278
|
-
self.signal = 0
|
|
279
|
-
|
|
280
|
-
@property
|
|
281
|
-
def pending_request(self) -> list[PendingRequest]:
|
|
282
|
-
return self.contexts.setdefault('pending_request', [])
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
class BarrierConfirmationLogicGroup(RacingConfirmationLogicGroup):
|
|
286
|
-
|
|
287
|
-
def __init__(self, parent: SignalLogicGroup, name: str = None):
|
|
288
|
-
super().__init__(
|
|
289
|
-
name=f'{parent.name}.Barrier' if name is None else name,
|
|
290
|
-
parent=parent
|
|
291
|
-
)
|
|
292
|
-
|
|
293
|
-
def confirm(self, pending_request: PendingRequest = None, uid: uuid.UUID = None):
|
|
294
|
-
if pending_request is None and uid is None:
|
|
295
|
-
assert len(self.pending_request) == 1, ValueError('Multiple pending requests found! Must assign uid or pending_request instance!')
|
|
296
|
-
pending_request = self.pending_request[0]
|
|
297
|
-
elif pending_request is None:
|
|
298
|
-
pending_request = self.__getitem__(uid=uid)
|
|
299
|
-
|
|
300
|
-
self.pending_request.remove(pending_request)
|
|
301
|
-
|
|
302
|
-
if self.pending_request:
|
|
303
|
-
return 0
|
|
304
|
-
|
|
305
|
-
sig = pending_request.sig
|
|
306
|
-
self.signal = sig
|
|
307
|
-
return sig
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
decision_graph/__init__.py,sha256=q9shYabVEpcXAI_sTJNV_dTx0Jt3SnnTEscpRQGnDs8,385
|
|
2
|
-
decision_graph/decision_tree/__init__.py,sha256=5kbQXFM_lVETYaEpU_hUyECbTW5LjDmJyocWE-A7PbA,1168
|
|
3
|
-
decision_graph/decision_tree/abc.py,sha256=f4acaPzOloksmdpL6SqZOqVt1mr1nO6lSMKg01ofO84,40440
|
|
4
|
-
decision_graph/decision_tree/collection.py,sha256=K9fob0e7493BSXik0zfPzVSFupQezz1zvABYvMAo27k,2403
|
|
5
|
-
decision_graph/decision_tree/exc.py,sha256=THgIIP8S2PyJ9HIyUbNRhKT1umHfmf3Nh4rYrV8ywXU,646
|
|
6
|
-
decision_graph/decision_tree/expression.py,sha256=_bd1U2tjHnCydoC1Ya6RwTasRbKweMzUsghXsDe4ZpA,16777
|
|
7
|
-
decision_graph/decision_tree/logic_group.py,sha256=-PkZJ9VzJf3WXRNmlepGeSRXBdf0K0o9yBr6xxeqvzI,9219
|
|
8
|
-
decision_graph/decision_tree/node.py,sha256=aO5X-_2RiY2bFKbexBFL0Ei2iF6_cCgESOQ-90c-Rn8,8599
|
|
9
|
-
pydecisiongraph-0.1.1.dist-info/LICENSE,sha256=HyVuytGSiAUQ6ErWBHTqt1iSGHhLmlC8fO7jTCuR8dU,16725
|
|
10
|
-
pydecisiongraph-0.1.1.dist-info/METADATA,sha256=IPt_FdqifrV6GSycPYwkxJbtdNPu3TVUuIzVJO2AI30,5456
|
|
11
|
-
pydecisiongraph-0.1.1.dist-info/WHEEL,sha256=jB7zZ3N9hIM9adW7qlTAyycLYW9npaWKLRzaoVcLKcM,91
|
|
12
|
-
pydecisiongraph-0.1.1.dist-info/top_level.txt,sha256=3_p81U9qj9sTh1K6a1ZE-JNv7LKHaCeavuzci28VjFk,15
|
|
13
|
-
pydecisiongraph-0.1.1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|