Belle II Software  release-05-01-25
state_machine.py
1 import basf2 as b2
2 from caf.state_machines import Machine, State
3 
4 # We set up a bunch of function callbacks to show the ordering of evaluation
5 # Notice that we always pass **kwargs so that they have access to anything that
6 # can be passed in.
7 
8 
9 def print_msg_before(**kwargs):
10  """
11  Callbacks on transitions have access to keyword arguments that you can
12  specify when calling a transition. But remember that all kwargs are passed
13  to ALL transition callbacks. Including both the before and after callbacks
14  """
15  b2.B2INFO(kwargs["msg_before"])
16 
17 
18 def print_msg_after(**kwargs):
19  """
20  Have to have a different kwarg name, otherwise the same argument from the
21  'before' callback will be used
22  """
23  b2.B2INFO(kwargs["msg_after"])
24 
25 
26 def enter_new_state(**kwargs):
27  """
28  Enter and exit callbacks have access to the prior and new state objects but NOT
29  the transition arguments.
30  """
31  b2.B2INFO("Entering state {0} from state {1}".format(kwargs["new_state"].name, kwargs["prior_state"].name))
32 
33 
34 def exit_old_state(**kwargs):
35  b2.B2INFO("Exiting state {0} to state {1}".format(kwargs["prior_state"].name, kwargs["new_state"].name))
36 
37 
38 def condition_true(**kwargs):
39  b2.B2INFO("Evaluating conditions")
40  return True
41 
42 
43 # Now build up a machine with some basic states and transitions between them
44 m1 = Machine()
45 m1.add_state(State("start", enter=enter_new_state, exit=exit_old_state)) # Can use a state object to add new ones
46 m1.add_state("running", enter=enter_new_state, exit=exit_old_state) # Don't have to use a state object though
47 m1.add_state("end", enter=enter_new_state, exit=exit_old_state)
48 
49 m1.add_transition(trigger="begin", source="start", dest="running",
50  conditions=condition_true, before=print_msg_before, after=print_msg_after)
51 m1.add_transition("finish", "running", "end",
52  conditions=condition_true, before=print_msg_before, after=print_msg_after)
53 
54 # have to set a start point
55 m1.initial_state = "start"
56 
57 # Note that because we didn't specify an initial state when creating the Machine we will get an orphaned default_initial
58 # state in the graph. Easily removable by hand or by adding an initial state in the Machine() initialisation.
59 m1.save_graph(filename="machine_graph.dot", graphname="Machine")
60 
61 # Run through the states passing in arguments to callbacks
62 b2.B2INFO("Currently in " + m1.state.name + " state.")
63 m1.begin(msg_before="About to run", msg_after="Now Running")
64 m1.finish(msg_before="Finishing", msg_after="Finished")
65 b2.B2INFO("Currently in " + m1.state.name + " state.")