-
-
Notifications
You must be signed in to change notification settings - Fork 103
Expand file tree
/
Copy pathstatechart_in_condition_machine.py
More file actions
115 lines (89 loc) · 3.55 KB
/
statechart_in_condition_machine.py
File metadata and controls
115 lines (89 loc) · 3.55 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
"""
In() guard condition -- Fellowship Coordination
=================================================
This example demonstrates the **In()** guard condition using ``StateChart``
with parallel states.
``In('state_id')`` checks whether a given state is currently active. This is
especially useful in parallel regions where one region's transitions depend
on the state of another region.
"""
from statemachine import State
from statemachine import StateChart
class FellowshipMachine(StateChart):
"""Fellowship coordination with parallel regions.
Two parallel regions track Frodo and Sam independently. The key
transition -- ``sam_to_mordor`` -- uses ``In('mordor_f')`` to ensure Sam
only follows Frodo to Mordor after Frodo has already arrived there.
"""
class quest(State.Parallel):
class frodo_path(State.Compound):
shire_f = State("Frodo in Shire", initial=True)
rivendell_f = State("Frodo at Rivendell")
mordor_f = State("Frodo in Mordor", final=True)
frodo_to_rivendell = shire_f.to(rivendell_f)
frodo_to_mordor = rivendell_f.to(mordor_f)
class sam_path(State.Compound):
shire_s = State("Sam in Shire", initial=True)
rivendell_s = State("Sam at Rivendell")
mordor_s = State("Sam in Mordor")
mount_doom_s = State("Sam at Mount Doom", final=True)
sam_to_rivendell = shire_s.to(rivendell_s)
# Sam can only go to Mordor when Frodo is already there
sam_to_mordor = rivendell_s.to(mordor_s, cond="In('mordor_f')")
sam_to_mount_doom = mordor_s.to(mount_doom_s)
victory = State("Victory", final=True)
done_state_quest = quest.to(victory)
# %%
# Initial state -- both in the Shire
# ------------------------------------
sm = FellowshipMachine()
vals = set(sm.configuration_values)
print(f"Start: {sorted(vals)}")
assert "shire_f" in vals
assert "shire_s" in vals
# %%
# Move both to Rivendell independently
# ---------------------------------------
sm.send("frodo_to_rivendell")
sm.send("sam_to_rivendell")
vals = set(sm.configuration_values)
print(f"Both at Rivendell: {sorted(vals)}")
assert "rivendell_f" in vals
assert "rivendell_s" in vals
# %%
# Sam can't go to Mordor yet -- In('mordor_f') is false
# -------------------------------------------------------
#
# Frodo hasn't reached Mordor, so ``In('mordor_f')`` evaluates to false
# and Sam's transition is blocked.
sm.send("sam_to_mordor")
vals = set(sm.configuration_values)
print(f"Sam blocked: {sorted(vals)}")
assert "rivendell_s" in vals # Sam still at Rivendell
# %%
# Frodo reaches Mordor -- now Sam can follow
# ---------------------------------------------
#
# After Frodo transitions to ``mordor_f``, the ``In('mordor_f')`` condition
# becomes true. Now sending ``sam_to_mordor`` will succeed.
sm.send("frodo_to_mordor")
vals = set(sm.configuration_values)
print(f"Frodo in Mordor: {sorted(vals)}")
assert "mordor_f" in vals
assert "rivendell_s" in vals # Sam still waiting
# %%
# Sam follows Frodo -- In() guard passes
# ----------------------------------------
sm.send("sam_to_mordor")
vals = set(sm.configuration_values)
print(f"Sam follows: {sorted(vals)}")
assert "mordor_s" in vals
# %%
# Both regions complete -- done.state fires
# -------------------------------------------
#
# When both parallel regions reach their final states, ``done.state.quest``
# fires automatically and transitions to ``victory``.
sm.send("sam_to_mount_doom")
print(f"Victory: {sorted(sm.configuration_values)}")
assert "victory" in sm.configuration_values