Merge pull request #1364 from forslund/bugfix/scheduled-event

Bugfix/scheduled event
pull/1424/head
Michael Nguyen 2018-02-13 22:34:51 -06:00 committed by GitHub
commit 50c7ab6c6e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 126 additions and 18 deletions

View File

@ -596,24 +596,26 @@ class MycroftSkill(object):
text = f.read().replace('{{', '{').replace('}}', '}')
return text.format(**data or {}).split('\n')
def add_event(self, name, handler, need_self=False):
def add_event(self, name, handler, need_self=False, once=False):
"""
Create event handler for executing intent
Args:
name: IntentParser name
handler: method to call
need_self: optional parameter, when called from a decorated
intent handler the function will need the self
variable passed as well.
need_self: optional parameter, when called from a decorated
intent handler the function will need the self
variable passed as well.
once: optional parameter, Event handler will be removed
after it has been run once.
"""
def wrapper(message):
try:
# Indicate that the skill handler is starting
name = get_handler_name(handler)
handler_name = get_handler_name(handler)
self.emitter.emit(Message("mycroft.skill.handler.start",
data={'handler': name}))
data={'handler': handler_name}))
stopwatch = Stopwatch()
with stopwatch:
@ -653,24 +655,29 @@ class MycroftSkill(object):
except Exception as e:
# Convert "MyFancySkill" to "My Fancy Skill" for speaking
name = re.sub("([a-z])([A-Z])", "\g<1> \g<2>", self.name)
handler_name = re.sub("([a-z])([A-Z])", "\g<1> \g<2>",
self.name)
# TODO: Localize
self.speak(
"An error occurred while processing a request in " +
name)
self.speak("An error occurred while processing a request in " +
handler_name)
LOG.error(
"An error occurred while processing a request in " +
self.name, exc_info=True)
# indicate completion with exception
self.emitter.emit(Message('mycroft.skill.handler.complete',
data={'handler': name,
data={'handler': handler_name,
'exception': e.message}))
# Indicate that the skill handler has completed
self.emitter.emit(Message('mycroft.skill.handler.complete',
data={'handler': name}))
data={'handler': handler_name}))
if once:
self.remove_event(name)
if handler:
self.emitter.on(name, wrapper)
if once:
self.emitter.once(name, wrapper)
else:
self.emitter.on(name, wrapper)
self.events.append((name, wrapper))
def remove_event(self, name):
@ -682,8 +689,15 @@ class MycroftSkill(object):
"""
for _name, _handler in self.events:
if name == _name:
self.events.remove((_name, _handler))
self.emitter.remove(_name, _handler)
try:
self.events.remove((_name, _handler))
except ValueError:
pass
try:
self.emitter.remove(_name, _handler)
except ValueError:
LOG.debug('{} is not registered in the emitter'.format(
_name))
def register_intent(self, intent_parser, handler, need_self=False):
"""
@ -946,12 +960,12 @@ class MycroftSkill(object):
Underlying method for schedle_event and schedule_repeating_event.
Takes scheduling information and sends it of on the message bus.
"""
data = data or {}
if not name:
name = self.name + handler.__name__
name = self._unique_name(name)
self.add_event(name, handler, False)
data = data or {}
self.add_event(name, handler, once=not repeat)
event_data = {}
event_data['time'] = time.mktime(when.timetuple())
event_data['event'] = name

View File

@ -20,6 +20,7 @@ import mock
from adapt.intent import IntentBuilder
from os.path import join, dirname, abspath
from re import error
from datetime import datetime
from mycroft.configuration import Configuration
from mycroft.messagebus.message import Message
@ -399,15 +400,108 @@ class MycroftSkillTest(unittest.TestCase):
self.assertEqual(s.location_pretty, None)
self.assertEqual(s.location_timezone, None)
@mock.patch.object(Configuration, 'get')
def test_add_event(self, mock_config_get):
test_config = {
'skills': {
}
}
mock_config_get.return_value = test_config
emitter = mock.MagicMock()
s = TestSkill1()
s.bind(emitter)
s.add_event('handler1', s.handler)
# Check that the handler was registered with the emitter
self.assertEqual(emitter.on.call_args[0][0], 'handler1')
# Check that the handler was stored in the skill
self.assertTrue('handler1' in zip(*s.events)[0])
@mock.patch.object(Configuration, 'get')
def test_remove_event(self, mock_config_get):
test_config = {
'skills': {
}
}
mock_config_get.return_value = test_config
emitter = mock.MagicMock()
s = TestSkill1()
s.bind(emitter)
s.add_event('handler1', s.handler)
self.assertTrue('handler1' in zip(*s.events)[0])
# Remove event handler
s.remove_event('handler1')
# make sure it's not in the event list anymore
self.assertTrue('handler1' not in zip(*s.events)[0])
# Check that the handler was registered with the emitter
self.assertEqual(emitter.remove.call_args[0][0], 'handler1')
@mock.patch.object(Configuration, 'get')
def test_add_scheduled_event(self, mock_config_get):
test_config = {
'skills': {
}
}
mock_config_get.return_value = test_config
emitter = mock.MagicMock()
s = TestSkill1()
s.bind(emitter)
s.schedule_event(s.handler, datetime.now(), name='sched_handler1')
# Check that the handler was registered with the emitter
self.assertEqual(emitter.once.call_args[0][0], '0:sched_handler1')
self.assertTrue('0:sched_handler1' in zip(*s.events)[0])
@mock.patch.object(Configuration, 'get')
def test_remove_scheduled_event(self, mock_config_get):
test_config = {
'skills': {
}
}
mock_config_get.return_value = test_config
emitter = mock.MagicMock()
s = TestSkill1()
s.bind(emitter)
s.schedule_event(s.handler, datetime.now(), name='sched_handler1')
# Check that the handler was registered with the emitter
self.assertTrue('0:sched_handler1' in zip(*s.events)[0])
s.cancel_scheduled_event('sched_handler1')
# Check that the handler was removed
self.assertEqual(emitter.remove.call_args[0][0], '0:sched_handler1')
self.assertTrue('0:sched_handler1' not in zip(*s.events)[0])
@mock.patch.object(Configuration, 'get')
def test_run_scheduled_event(self, mock_config_get):
test_config = {
'skills': {
}
}
mock_config_get.return_value = test_config
emitter = mock.MagicMock()
s = TestSkill1()
with mock.patch.object(s, '_settings',
create=True, value=mock.MagicMock()):
s.bind(emitter)
s.schedule_event(s.handler, datetime.now(), name='sched_handler1')
# Check that the handler was registered with the emitter
emitter.once.call_args[0][1](Message('message'))
# Check that the handler was run
self.assertTrue(s.handler_run)
# Check that the handler was removed from the list of registred
# handler
self.assertTrue('0:sched_handler1' not in zip(*s.events)[0])
class TestSkill1(MycroftSkill):
def __init__(self):
super(TestSkill1, self).__init__()
self.handler_run = False
""" Test skill for normal intent builder syntax """
def initialize(self):
i = IntentBuilder('a').require('Keyword').build()
self.register_intent(i, self.handler)
def handler(self, message):
pass
self.handler_run = True
def stop(self):
pass