-
Notifications
You must be signed in to change notification settings - Fork 19
Expand file tree
/
Copy pathmachine.py
More file actions
111 lines (87 loc) · 3.33 KB
/
machine.py
File metadata and controls
111 lines (87 loc) · 3.33 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
from typing import Dict, List
from xstate.algorithm import (
enter_states,
get_configuration_from_state,
macrostep,
main_event_loop,
)
from xstate.event import Event
from xstate.state import State
from xstate.state_node import StateNode
class Machine:
id: str
root: StateNode
_id_map: Dict[str, StateNode]
config: object
states: Dict[str, StateNode]
actions: List[lambda: None]
def __init__(self, config: object, actions={}):
self.id = config["id"]
self._id_map = {}
self.root = StateNode(
config, machine=self, key=config.get("id", "(machine)"), parent=None
)
self.states = self.root.states
self.config = config
self.actions = actions
def transition(self, state: State, event: str):
configuration = get_configuration_from_state(
from_node=self.root, state_value=state.value, partial_configuration=set()
)
(configuration, _actions) = main_event_loop(configuration, Event(event))
actions, warnings = self._get_actions(_actions)
for w in warnings:
print(w)
return State(configuration=configuration, context={}, actions=actions)
def _get_actions(self, actions) -> List[lambda: None]:
result = []
errors = []
for action in actions:
if action.type in self.actions:
result.append(self.actions[action.type])
elif callable(action.type):
result.append(action.type)
else:
errors.append("No '{}' action".format(action.type))
return result, errors
def state_from(self, state_value) -> State:
configuration = self._get_configuration(state_value=state_value)
return State(configuration=configuration, context=None)
def _register(self, state_node: StateNode):
state_node.machine = self
self._id_map[state_node.id] = state_node
def _get_by_id(self, id: str) -> StateNode:
return self._id_map.get(id, None)
def _get_configuration(self, state_value, parent=None) -> List[StateNode]:
if parent is None:
parent = self.root
if isinstance(state_value, str):
state_node = parent.states.get(state_value, None)
if state_node is None:
raise ValueError(f"State node {state_value} is missing")
return [state_node]
configuration = []
for key in state_value.keys():
state_node = parent.states.get(key)
configuration.append(state_node)
configuration += self._get_configuration(
state_value.get(key), parent=state_node
)
return configuration
@property
def initial_state(self) -> State:
(configuration, _actions, internal_queue) = enter_states(
[self.root.initial],
configuration=set(),
states_to_invoke=set(),
history_value={},
actions=[],
internal_queue=[],
)
(configuration, _actions) = macrostep(
configuration=configuration, actions=_actions, internal_queue=internal_queue
)
actions, warnings = self._get_actions(_actions)
for w in warnings:
print(w)
return State(configuration=configuration, context={}, actions=actions)