def _trigger(self, _model, _machine, *args, **kwargs): state_tree = _machine._build_state_tree( getattr(_model, _machine.model_attribute), _machine.state_cls.separator) state_tree = reduce(dict.get, _machine.get_global_name(join=False), state_tree) ordered_states = _resolve_order(state_tree) done = [] res = None for state_path in ordered_states: state_name = _machine.state_cls.separator.join(state_path) if state_name not in done and state_name in self.transitions: state = _machine.get_state(state_name) event_data = EventData(state, self, _machine, _model, args=args, kwargs=kwargs) event_data.source_name = state_name event_data.source_path = copy.copy(state_path) res = self._process(event_data) if res: elems = state_path while elems: done.append(_machine.state_cls.separator.join(elems)) elems.pop() return res
def on_state_changed(self, event: EventData): """Called on each state change""" # TODO: check if kwargs already have keys event.kwargs["position"] = self.position.to_dict() route = self.engine.route if route: event.kwargs["origin"] = route.origin.to_dict() event.kwargs["destination"] = route.destination.to_dict() # distance in km event.kwargs["trip_distance"] = round( route.traveled_distance(self.engine.now), 3 ) # duration in clock steps event.kwargs["trip_duration"] = round( route.traveled_time(self.engine.now), 3 ) itinerary = event.kwargs.get("itinerary") if itinerary and itinerary.next_jobs: next_job = itinerary.next_jobs[0] if next_job.is_pickup(): event.kwargs["pickup"] = next_job.booking.id elif next_job.is_dropoff(): event.kwargs["dropoff"] = next_job.booking.id super().on_state_changed(event)
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)
def on_state_changed(self, event: EventData): """The function is called by the state machine on each state change. Parameters ---------- event : EventData Contains information describing state change like a current state and a new state """ if event.transition.dest == States.pending.value: # TODO: check if kwargs already have keys event.kwargs["position"] = self.pickup.to_dict() event.kwargs["dropoff"] = self.dropoff.to_dict() if event.transition.dest in ( States.pending.value, States.matched.value, States.pickup.value, States.expired.value, States.waiting_dropoff.value, States.waiting_pickup.value, States.expired.value, ): # NOTE: created position can be different from pickup position # but this is not supported at the moment event.kwargs["position"] = self.pickup.to_dict() if event.transition.dest in (States.dropoff.value, States.complete.value): # NOTE: pickup event.kwargs["position"] = self.dropoff.to_dict() itinerary = event.kwargs.get("itinerary") if itinerary: event.kwargs["vid"] = itinerary.vehicle.id super().on_state_changed(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
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. """ event = EventData(self.get_model_state(model), Event('to', self), self, model, args=args, kwargs=kwargs) self._create_transition(getattr(model, self.model_attribute), state_name).execute(event)
def GET(self, action): super(DoorOpenClose, self).GET() if action not in ('open', 'close'): raise web.seeother('/') coop = Coop() event = EventData(None, None, None, None, None, {'switches': coop.door_dual_sensor}) if action == 'open': coop.door.open(event) state = 'open' else: coop.door.close(event) state = 'closed' day_night = coop.sunset_sunrise_sensor.state if day_night == 'invalid': day_night = 'night' coop.door.set_state('manual-{}-{}'.format(state, day_night)) raise web.seeother('/')
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)