Transitions and events

A machine moves from state to state through transitions. These transitions are caused by events.

Event

An event is an external signal that something has happened. They are sent to a state machine, and allow the state machine to react.

An event start a Transition, can be thought of as a “cause” that initiates a change in the state of the system.

In python-statemachine, an event is specified as an attribute of the statemachine class declaration, or diretly on the event parameter on a Transition.

Transition

In an executing state machine, a transition is the instantaneous transfer from one state to another. In a state machine, a transition tells us what happens when an Event occurs.

A self transition is a transition that goes from and to the same state.

A transition can define actions that will be executed whenever that transition is executed.

class statemachine.transition.Transition(source, target, event=None, validators=None, cond=None, unless=None, on=None, before=None, after=None)[source]

A transition holds reference to the source and target state.

Parameters
  • source (State) – The origin state of the transition.

  • target (State) – The target state of the transition.

  • event (Optional[Union[str, List[str]]]) – List of designators of events that trigger this transition. Can be either a list of strings, or a space-separated string list of event descriptors.

  • validators (Optional[Union[str, Callable, List[Callable]]]) – The validation callbacks to be invoked before the transition is executed.

  • cond (Optional[Union[str, Callable, List[Callable]]]) – The condition callbacks to be invoked before the transition is executed that should evaluate to True.

  • unless (Optional[Union[str, Callable, List[Callable]]]) – The condition callbacks to be invoked if the cond is False before the transition is executed.

  • on (Optional[Union[str, Callable, List[Callable]]]) – The callbacks to be invoked when the transition is executed.

  • before (Optional[Union[str, Callable, List[Callable]]]) – The callbacks to be invoked before the transition is executed.

  • after (Optional[Union[str, Callable, List[Callable]]]) – The callbacks to be invoked after the transition is executed.

Self transition

A transition that goes from a state to itself.

Syntax:

>>> draft = State("Draft")

>>> draft.to.itself()
TransitionList([Transition(State('Draft', ...

Example

Consider this traffic light machine as example:

TrafficLightMachine

There’re tree transitions, one starting from green to yellow, another from yellow to red, and another from red back to green. All these transitions are triggered by the same Event called cycle.

This statemachine could be expressed in python-statemachine as:

 1"""
 2Traffic light machine
 3---------------------
 4
 5Demonstrates the concept of ``cycle`` states.
 6
 7"""
 8from statemachine import State
 9from statemachine import StateMachine
10
11
12class TrafficLightMachine(StateMachine):
13    "A traffic light machine"
14    green = State("Green", initial=True)
15    yellow = State("Yellow")
16    red = State("Red")
17
18    cycle = green.to(yellow) | yellow.to(red) | red.to(green)
19
20    def on_cycle(self, event_data=None):
21        return "Running {} from {} to {}".format(
22            event_data.event,
23            event_data.source.id,
24            event_data.target.id,
25        )

At line 18, you can say that this code defines three transitions:

  • green.to(yellow)

  • yellow.to(red)

  • red.to(green)

And these transitions are assigned to the Event cycle defined at class level.

When an Event is sent to a stamemachine:

  1. Uses the current State to check for available transitions.

  2. For each possible transition, it checks for those that matches the received Event.

  3. The target state, if the transition succeeds, is determined by a transisition that an event matches and;

  4. All Validators and guards, including Actions atached to the on_<event> and before_<event> callbacks.

Triggering events

By direct calling the event:

>>> machine = TrafficLightMachine()

>>> machine.cycle()
'Running cycle from green to yellow'

>>> machine.current_state.id
'yellow'

In a running (interpreted) machine, events are sent:

>>> machine.send("cycle")
'Running cycle from yellow to red'

>>> machine.current_state.id
'red'

You can also pass positional and keyword arguments, that will be propagated to the actions. On this example, the :code:TrafficLightMachine implements an action that echoes back the params informed.

1class TrafficLightMachine(StateMachine):
2    "A traffic light machine"
3    green = State("Green", initial=True)
4    yellow = State("Yellow")

This action is executed before the transition associated with cycle event is activated, so you can also raise an exception at this point to stop a transition to occur.

>>> machine.current_state.id
'red'

>>> machine.cycle()
'Running cycle from red to green'

>>> machine.current_state.id
'green'