    def __init__(self, states, transitions, initial, during=None, on_enter=None,
                 on_exit=None):
        '''
        Creates a new state machine. The `during`, `on_enter`, and `on_exit`
        dictionaries are all optional. Additionally, each is free to have
        as few or as many of each state as desired, i.e. leaving out states
        is fine.
        Args:
            states (List[str]): A list of all possible states in the FSM.
            transitions (List[Dict[str, function]]): Dictionaries of transitions
                and conditions. Each dictionary must contain the following keys:
                    source (str): The source state of the transition.
                    dest (str): The destination state of the transition.
                Each dictionary may contain the following keys:
                    condition (function): A condition that must be true for the
                        transition to occur. If no condition is provided then the
                        state machine will transition on a step.
                    action (function): A function to be executed while the
                        transition occurs.
            during (Dict[str, function]): A mapping of states to functions to
                execute while in that state.
            initial (str): The state to start in.
            on_enter (Dict[str, function]): A mapping of states to functions to
                execute when entering that state.
            on_exit (Dict[str, function]): A mapping of states to functions to
                execute when exiting from that state.
        '''
        if during is None:
            during = {}
        if on_enter is None:
            on_enter = {}
        if on_exit is None:
            on_exit = {}

        # Build states
        if sorted(list(set(states))) != sorted(states):
            raise StateMachineException('Duplicate state names encountered:\n{0}'.format(states))

        self._states = {}
        for state in states:
            self._states[state] = State(state,
                                        during.get(state, None),
                                        on_enter.get(state, None),
                                        on_exit.get(state, None)
                                        )

        # Set initial state
        if initial not in self._states:
            raise StateMachineException('Invalid initial state: {0}'.format(initial))
        self.state = self._states[initial]

        # Build transitions
        self._transitions = defaultdict(list)
        for transition in transitions:
            # Validate transition for correct states
            if transition['source'] not in self._states:
                raise StateMachineException('Invalid source state: {0}'
                    .format(transition['source']))
            if transition['dest'] not in self._states:
                raise StateMachineException('Invalid destination state: {0}'
                    .format(transition['dest']))

            source_state = self._states[transition['source']]
            dest_state = self._states[transition['dest']]
            self._transitions[transition['source']].append(Transition(source_state,
                                                               dest_state,
                                                               transition.get('condition', None),
                                                               transition.get('action', None)
                                                               ))
Creates a new state machine. The `during`, `on_enter`, and `on_exit`
dictionaries are all optional. Additionally, each is free to have
as few or as many of each state as desired, i.e. leaving out states
is fine.
Args:
states (List[str]): A list of all possible states in the FSM.
transitions (List[Dict[str, function]]): Dictionaries of transitions
and conditions. Each dictionary must contain the following keys:
source (str): The source state of the transition.
dest (str): The destination state of the transition.
Each dictionary may contain the following keys:
condition (function): A condition that must be true for the
transition to occur. If no condition is provided then the
state machine will transition on a step.
action (function): A function to be executed while the
transition occurs.
during (Dict[str, function]): A mapping of states to functions to
execute while in that state.
initial (str): The state to start in.
on_enter (Dict[str, function]): A mapping of states to functions to
execute when entering that state.
on_exit (Dict[str, function]): A mapping of states to functions to
execute when exiting from that state.
securitybot/state_machine.py