def enter(self, event_data):
     """ Extends transitions.core.State.enter. Throws a `MachineError` if there is
         no leaving transition from this state and 'accepted' is not in self.tags.
     """
     if not event_data.machine.get_triggers(self.name) and not self.is_accepted:
         raise MachineError("Error state '%s' reached!" % (self.name,))
     super(Error, self).enter(event_data)
    async def _process(self, trigger):
        if not self.has_queue:
            if not self._transition_queue:
                return (await trigger())
            else:
                raise MachineError(
                    "Attempt to process events synchronously while transition queue is not empty!"
                )

        self._transition_queue.append(trigger)
        if len(self._transition_queue) > 1:
            return True

        while self._transition_queue:
            try:
                callback = self._transition_queue[0]()

                if asyncio.iscoroutine(callback):
                    await callback

                self._transition_queue.popleft()
            except Exception:
                self._transition_queue.clear()
                raise
        return True
    async def _process(self, trigger):
        # default processing
        if not self.has_queue:
            if not self._transition_queue:
                # if trigger raises an Error, it has to be handled by the Machine.process caller
                return await trigger()
            else:
                raise MachineError(
                    "Attempt to process events synchronously while transition queue is not empty!"
                )

        self._transition_queue.append(trigger)
        # another entry in the queue implies a running transition; skip immediate execution
        if len(self._transition_queue) > 1:
            return True

        # execute as long as transition queue is not empty ToDo: not tested!
        while self._transition_queue:
            try:
                await self._transition_queue[0]()
                self._transition_queue.popleft()
            except Exception:
                # if a transition raises an exception, clear queue and delegate exception handling
                self._transition_queue.clear()
                raise
        return True
Exemple #4
0
 def _check_event_result(self, res, model, trigger):
     if res is None:
         state_name = getattr(model, self.model_attribute)
         msg = "%sCan't trigger event %s from state %s!" % (
             self.name, trigger, state_name)
         state = self.get_state(state_name)
         ignore = state.ignore_invalid_triggers if state.ignore_invalid_triggers is not None \
             else self.ignore_invalid_triggers
         if ignore:
             _LOGGER.warning(msg)
             res = False
         else:
             raise MachineError(msg)
     return res
Exemple #5
0
 def _trigger(self, model, *args, **kwargs):
     state = self.machine.get_model_state(model)
     while state.parent and state.name not in self.transitions:
         state = state.parent
     if state.name not in self.transitions:
         msg = "%sCan't trigger event %s from state %s!" % (
             self.machine.name, self.name,
             self.machine.get_model_state(model))
         if self.machine.get_model_state(model).ignore_invalid_triggers:
             _LOGGER.warning(msg)
         else:
             raise MachineError(msg)
     event_data = EventData(state,
                            self,
                            self.machine,
                            model,
                            args=args,
                            kwargs=kwargs)
     return self._process(event_data)
 async def _trigger(self, model, *args, **kwargs):
     state = self.machine.get_state(model.state)
     if state.name not in self.transitions:
         msg = "%sCan't trigger event %s from state %s!" % (
             self.machine.name, self.name, state.name)
         ignore = state.ignore_invalid_triggers if state.ignore_invalid_triggers is not None \
             else self.machine.ignore_invalid_triggers
         if ignore:
             _LOGGER.warning(msg)
             return False
         else:
             raise MachineError(msg)
     event_data = EventData(state,
                            self,
                            self.machine,
                            model,
                            args=args,
                            kwargs=kwargs)
     return await self._process(event_data)
Exemple #7
0
    def to_state(self, model, state_name, *args, **kwargs):
        """ Helper function to add go to states in case a custom state separator is used.
        Args:
            model (class): The model that should be used.
            state_name (str): Name of the destination state.
        """

        current_state = getattr(model, self.model_attribute)
        if isinstance(current_state, list):
            raise MachineError("Cannot use 'to_state' from parallel state")

        event = EventData(self.get_state(current_state),
                          Event('to', self),
                          self,
                          model,
                          args=args,
                          kwargs=kwargs)
        event.source_name = current_state
        event.source_path = current_state.split(self.state_cls.separator)
        self._create_transition(current_state, state_name).execute(event)
    async def _trigger(self, model, *args, **kwargs):
        state = self.machine.get_state(model.state)
        while state.parent and state.name not in self.transitions:
            state = state.parent
        if state.name not in self.transitions:
            msg = "%sCan't trigger event %s from state %s!" % (
                self.machine.name, self.name, model.state)
            if self.machine.get_state(model.state).ignore_invalid_triggers:
                logger.warning(msg)
            else:
                raise MachineError(msg)
        event_data = EventData(self.machine.get_state(model.state),
                               self,
                               self.machine,
                               model,
                               args=args,
                               kwargs=kwargs)

        for func in self.machine.prepare_event:
            await self.machine._callback(func, event_data)
            logger.debug(
                "Executed machine preparation callback '%s' before conditions."
                % func)

        try:
            for t in self.transitions[state.name]:
                event_data.transition = t
                transition_result = await t.execute(event_data)
                if transition_result:
                    event_data.result = True
                    break
        except Exception as e:
            event_data.error = e
            raise
        finally:
            for func in self.machine.finalize_event:
                await self.machine._callback(func, event_data)
                logger.debug("Executed machine finalize callback '%s'." % func)
        return event_data.result