-
-
Notifications
You must be signed in to change notification settings - Fork 103
Expand file tree
/
Copy pathstatechart_history_machine.py
More file actions
125 lines (93 loc) · 3.75 KB
/
statechart_history_machine.py
File metadata and controls
125 lines (93 loc) · 3.75 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
112
113
114
115
116
117
118
119
120
121
122
123
124
125
"""
History states -- Gollum's dual personality
============================================
This example demonstrates history pseudo-states using ``StateChart``.
A history state records the active child of a compound state when it is
exited. Re-entering via the history state restores the previously active
child instead of starting from the initial child.
Both shallow history (``HistoryState()``) and deep history
(``HistoryState(type="deep")``) are shown.
"""
from statemachine import HistoryState
from statemachine import State
from statemachine import StateChart
class PersonalityMachine(StateChart):
"""Gollum's dual personality with shallow history.
The ``personality`` compound has two children: ``smeagol`` and ``gollum``.
When Gollum leaves the ``personality`` state and returns via the history
pseudo-state, the previously active personality is restored.
"""
class personality(State.Compound):
smeagol = State("Smeagol", initial=True)
gollum = State("Gollum")
h = HistoryState()
dark_side = smeagol.to(gollum)
light_side = gollum.to(smeagol)
outside = State("Outside")
leave = personality.to(outside)
return_via_history = outside.to(personality.h)
# %%
# Shallow history remembers the last child
# ------------------------------------------
sm = PersonalityMachine()
print(f"Initial: {sorted(sm.configuration_values)}")
assert "smeagol" in sm.configuration_values
# Switch to Gollum, then leave
sm.send("dark_side")
print(f"Gollum active: {sorted(sm.configuration_values)}")
assert "gollum" in sm.configuration_values
sm.send("leave")
print(f"Left: {sorted(sm.configuration_values)}")
assert {"outside"} == set(sm.configuration_values)
# Return via history -> Gollum is restored
sm.send("return_via_history")
print(f"History restored: {sorted(sm.configuration_values)}")
assert "gollum" in sm.configuration_values
assert "personality" in sm.configuration_values
# %%
# Multiple exit/reentry cycles
# ------------------------------
#
# History updates each time the compound is exited.
sm.send("light_side")
print(f"Switched to Smeagol: {sorted(sm.configuration_values)}")
assert "smeagol" in sm.configuration_values
sm.send("leave")
sm.send("return_via_history")
print(f"Smeagol restored: {sorted(sm.configuration_values)}")
assert "smeagol" in sm.configuration_values
# %%
# Deep history with nested compounds
# ------------------------------------
#
# Deep history remembers the exact leaf state in nested compounds.
class DeepPersonalityMachine(StateChart):
"""A machine with nested compounds and deep history."""
class realm(State.Compound):
class inner(State.Compound):
entrance = State("Entrance", initial=True)
chamber = State("Chamber")
explore = entrance.to(chamber)
assert isinstance(inner, State)
h = HistoryState(type="deep") # type: ignore[has-type]
bridge = State("Bridge", final=True)
flee = inner.to(bridge)
outside = State("Outside")
escape = realm.to(outside)
return_deep = outside.to(realm.h) # type: ignore[has-type]
sm2 = DeepPersonalityMachine()
print(f"\nDeep history initial: {sorted(sm2.configuration_values)}")
assert "entrance" in sm2.configuration_values
# Move to the inner leaf state
sm2.send("explore")
print(f"Explored chamber: {sorted(sm2.configuration_values)}")
assert "chamber" in sm2.configuration_values
# Exit and return via deep history
sm2.send("escape")
print(f"Escaped: {sorted(sm2.configuration_values)}")
assert {"outside"} == set(sm2.configuration_values)
sm2.send("return_deep")
print(f"Deep history restored: {sorted(sm2.configuration_values)}")
assert "chamber" in sm2.configuration_values
assert "inner" in sm2.configuration_values
assert "realm" in sm2.configuration_values