Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.
{'trigger': 'forward', 'source': 'A', 'dest': 'B'},
{'trigger': 'forward', 'source': 'B', 'dest': 'C%s1' % State.separator},
{'trigger': 'backward', 'source': 'C', 'dest': 'B'},
{'trigger': 'backward', 'source': 'B', 'dest': 'A'},
{'trigger': 'calc', 'source': '*', 'dest': 'C'},
]
walker = Machine(states=new_states, transitions=new_transitions, before_state_change='watch',
after_state_change='look_back', initial='A')
walker.watch = lambda: 'walk'
walker.look_back = lambda: 'look_back'
walker.check = lambda: 'check'
walker.clear = lambda: 'clear'
with self.assertRaises(MachineError):
walker.increase()
self.assertEqual(walker.state, 'A')
walker.forward()
walker.forward()
self.assertEqual(walker.state, 'C%s1' % State.separator)
walker.increase()
self.assertEqual(walker.state, 'C%s2' % State.separator)
walker.reset()
self.assertEqual(walker.state, 'C%s1' % State.separator)
walker.to_A()
self.assertEqual(walker.state, 'A')
walker.calc()
self.assertEqual(walker.state, 'C')
def test_ignore_invalid_triggers(self):
a_state = State('A')
transitions = [['a_to_b', 'A', 'B']]
# Exception is triggered by default
b_state = State('B')
m1 = Machine('self', states=[a_state, b_state], transitions=transitions,
initial='B')
with self.assertRaises(MachineError):
m1.a_to_b()
# Set default value on machine level
m2 = Machine('self', states=[a_state, b_state], transitions=transitions,
initial='B', ignore_invalid_triggers=True)
m2.a_to_b()
# Exception is suppressed, so this passes
b_state = State('B', ignore_invalid_triggers=True)
m3 = Machine('self', states=[a_state, b_state], transitions=transitions,
initial='B')
m3.a_to_b()
# Set for some states but not others
new_states = ['C', 'D']
m1.add_states(new_states, ignore_invalid_triggers=True)
m1.to_D()
m1.a_to_b() # passes because exception suppressed for D
m1.to_B()
self.assertEqual(m.model.state, 'B')
self.assertEqual(m.model.level, 3)
m.model.move()
self.assertEqual(m.model.state, 'C')
self.assertEqual(m.model.level, 5)
# State does not advance, but increase_level still runs
m.model.move()
self.assertEqual(m.model.state, 'C')
self.assertEqual(m.model.level, 7)
# An invalid transition shouldn't execute the callback
try:
m.model.dont_move()
except MachineError as e:
self.assertTrue("Can't trigger event" in str(e))
self.assertEqual(m.model.state, 'C')
self.assertEqual(m.model.level, 7)
{'trigger': 'backward', 'source': 'B', 'dest': 'A'},
{'trigger': 'calc', 'source': '*', 'dest': 'C%s1' % State.separator},
]
walker = Machine(states=new_states, transitions=new_transitions, before_state_change='watch',
after_state_change='look_back', initial='A')
walker.watch = lambda: 'walk'
walker.look_back = lambda: 'look_back'
counter.increase()
counter.increase()
counter.done()
self.assertEqual(counter.state, 'finished')
with self.assertRaises(MachineError):
walker.increase()
self.assertEqual(walker.state, 'A')
walker.forward()
walker.forward()
self.assertEqual(walker.state, 'C%s1' % State.separator)
walker.increase()
self.assertEqual(walker.state, 'C%s2' % State.separator)
walker.reset()
self.assertEqual(walker.state, 'C%s1' % State.separator)
walker.to_A()
self.assertEqual(walker.state, 'A')
walker.calc()
self.assertEqual(walker.state, 'C%s1' % State.separator)
walker.increase()
walker.increase()
walker.done()
def execute(self) -> response.Response:
"""Called when the user specifies an intent for this skill"""
intent = self.attributes.intent
previous_state = self.state
# backup attributes in case of invalid FSM transition
attributes_backup = self.attributes
try:
# trigger is added by transitions library
self.trigger(intent)
current_state = self.state
logger.info(f"Changed from {previous_state} to {current_state} through {intent}")
self.attributes.state = current_state
return self.get_current_state_response()
except MachineError as exception:
logger.error(str(exception))
# reset attributes
self.states.attributes = attributes_backup
return response.NOT_UNDERSTOOD
def go(self, state, **kwargs): # pylint: disable=C0103
"""Try to move the state machine to the given state.
Args:
state (str): Desired state
kwargs (dict): Arguments
"""
try:
self.trigger(state, **kwargs) # pylint: disable=E1101
except (MachineError, AttributeError) as err:
self._logger.error('Could not trigger "%s": %s', state, err)
self.logger.debug("Keep-alive timeout=%d" % client_session.keep_alive)
handler.attach(client_session, reader, writer)
self._sessions[client_session.client_id] = (client_session, handler)
authenticated = yield from self.authenticate(client_session, self.listeners_config[listener_name])
if not authenticated:
yield from writer.close()
server.release_connection() # Delete client from connections list
return
while True:
try:
client_session.transitions.connect()
break
except (MachineError, ValueError):
# Backwards compat: MachineError is raised by transitions < 0.5.0.
self.logger.warning("Client %s is reconnecting too quickly, make it wait" % client_session.client_id)
# Wait a bit may be client is reconnecting too fast
yield from asyncio.sleep(1, loop=self._loop)
yield from handler.mqtt_connack_authorize(authenticated)
yield from self.plugins_manager.fire_event(EVENT_BROKER_CLIENT_CONNECTED, client_id=client_session.client_id)
self.logger.debug("%s Start messages handling" % client_session.client_id)
yield from handler.start()
self.logger.debug("Retained messages queue size: %d" % client_session.retained_messages.qsize())
yield from self.publish_session_retained_messages(client_session)
# Init and start loop for handling client messages (publish, subscribe/unsubscribe, disconnect)
disconnect_waiter = asyncio.ensure_future(handler.wait_disconnect(), loop=self._loop)
subscribe_waiter = asyncio.ensure_future(handler.get_next_pending_subscription(), loop=self._loop)
def acknowledge_delivery(self):
try:
self._ack_waiter.set_result(True)
except MachineError:
raise HBMQTTException(
'Invalid call to method acknowledge_delivery on in-flight messages with QOS=%d, state=%s' %
(self.qos, self.state))
@asyncio.coroutine
def shutdown(self):
"""
Stop broker instance.
Closes all connected session, stop listening on network socket and free resources.
"""
try:
self._sessions = dict()
self._subscriptions = dict()
self._retained_messages = dict()
self.transitions.shutdown()
except (MachineError, ValueError) as exc:
# Backwards compat: MachineError is raised by transitions < 0.5.0.
self.logger.debug("Invalid method call at this moment: %s" % exc)
raise BrokerException("Broker instance can't be stopped: %s" % exc)
# Fire broker_shutdown event to plugins
yield from self.plugins_manager.fire_event(EVENT_BROKER_PRE_SHUTDOWN)
# Stop broadcast loop
if self._broadcast_task:
self._broadcast_task.cancel()
if self._broadcast_queue.qsize() > 0:
self.logger.warning("%d messages not broadcasted" % self._broadcast_queue.qsize())
for listener_name in self._servers:
server = self._servers[listener_name]
yield from server.close_instance()
print("{} -> {}".format(old, p.state))
old = p.state
print("\nrandom trigger (stay in current state or go to terminated 50/50)")
p.random_trigger()
print("{} -> {}".format(old, p.state))
old = p.state
print("\ninterrupt trigger")
p.interrupt()
print("{} -> {}".format(old, p.state))
print('\nFrom "terminated" we cannot trigger a "start" event')
try:
p.start()
except MachineError as e:
print(e)