def _pre_process_event(self, event):
     current = self._current
     if current is None:
         raise excp.NotInitialized("Can not process event '%s'; the state"
                                   " machine hasn't been initialized" %
                                   event)
     if self._states[current.name]['terminal']:
         raise excp.InvalidState("Can not transition from terminal"
                                 " state '%s' on event '%s'" %
                                 (current.name, event))
     if event not in self._transitions[current.name]:
         raise excp.NotFound("Can not transition from state '%s' on"
                             " event '%s' (no defined transition)" %
                             (current.name, event))
    def add_transition(self, start, end, event, replace=False):
        """Adds an allowed transition from start -> end for the given event.

        :param start: starting state
        :param end: ending state
        :param event: event that causes start state to
                      transition to end state
        :param replace: replace existing event instead of raising a
                        :py:class:`~automaton.exceptions.Duplicate` exception
                        when the transition already exists.
        """
        if self.frozen:
            raise excp.FrozenMachine()
        if start not in self._states:
            raise excp.NotFound("Can not add a transition on event '%s' that"
                                " starts in a undefined state '%s'" %
                                (event, start))
        if end not in self._states:
            raise excp.NotFound("Can not add a transition on event '%s' that"
                                " ends in a undefined state '%s'" %
                                (event, end))
        if self._states[start]['terminal']:
            raise excp.InvalidState("Can not add a transition on event '%s'"
                                    " that starts in the terminal state '%s'" %
                                    (event, start))
        if event in self._transitions[start] and not replace:
            target = self._transitions[start][event]
            if target.name != end:
                raise excp.Duplicate(
                    "Cannot add transition from"
                    " '%(start_state)s' to '%(end_state)s'"
                    " on event '%(event)s' because a"
                    " transition from '%(start_state)s'"
                    " to '%(existing_end_state)s' on"
                    " event '%(event)s' already exists." % {
                        'existing_end_state': target.name,
                        'end_state': end,
                        'event': event,
                        'start_state': start
                    })
        else:
            target = _Jump(end, self._states[end]['on_enter'],
                           self._states[start]['on_exit'])
            self._transitions[start][event] = target
    def initialize(self, start_state=None):
        """Sets up the state machine (sets current state to start state...).

        :param start_state: explicit start state to use to initialize the
                            state machine to. If ``None`` is provided then
                            the machine's default start state will be used
                            instead.
        """
        if start_state is None:
            start_state = self._default_start_state
        if start_state not in self._states:
            raise excp.NotFound("Can not start from a undefined"
                                " state '%s'" % (start_state))
        if self._states[start_state]['terminal']:
            raise excp.InvalidState("Can not start from a terminal"
                                    " state '%s'" % (start_state))
        # No on enter will be called, since we are priming the state machine
        # and have not really transitioned from anything to get here, we will
        # though allow on_exit to be called on the event that causes this
        # to be moved from...
        self._current = _Jump(start_state, None,
                              self._states[start_state]['on_exit'])