Skip to content

Commit 72dfcab

Browse files
committed
refactor/standardize_usage_of_skill_id (#28)
This commit changes every usage of skill name to the deterministic skill_id There are several references in the code base to MycroftSkill self.name, this is not deterministic, by default it takes the name of the class but can be defined by skill developers and change in each skill update. self.name/self.skill_id are used in the __init__ method, but skill_id is not ensured to be defined at this step, potentially introducing issues depending on when certain methods are called, this is particularly troublesome when skills use the __init__ method since behavior may change depending on when super() is called
1 parent 7a9d7bc commit 72dfcab

File tree

2 files changed

+57
-58
lines changed

2 files changed

+57
-58
lines changed

mycroft/skills/event_scheduler.py

Lines changed: 25 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -165,8 +165,7 @@ def schedule_event(self, event, sched_time, repeat=None,
165165

166166
# Don't schedule if the event is repeating and already scheduled
167167
if repeat and event in self.events:
168-
LOG.debug('Repeating event {} is already scheduled, discarding'
169-
.format(event))
168+
LOG.debug(f'Repeating event {event} is already scheduled, discarding')
170169
else:
171170
# add received event and time
172171
event_list.append((sched_time, repeat, data, context))
@@ -241,7 +240,7 @@ def get_event_handler(self, message):
241240
with self.event_lock:
242241
if event_name in self.events:
243242
event = self.events[event_name]
244-
emitter_name = 'mycroft.event_status.callback.{}'.format(event_name)
243+
emitter_name = f'mycroft.event_status.callback.{event_name}'
245244
self.bus.emit(message.reply(emitter_name, data=event))
246245

247246
def store(self):
@@ -281,19 +280,30 @@ def shutdown(self):
281280
class EventSchedulerInterface:
282281
"""Interface for accessing the event scheduler over the message bus."""
283282

284-
def __init__(self, name, sched_id=None, bus=None):
285-
self.name = name
286-
self.sched_id = sched_id or self.__class__.__name__
283+
def __init__(self, name=None, sched_id=None, bus=None):
284+
self.name = name or self.__class__.__name__
285+
# we can not rename the sched_id keyword argument
286+
# because of backwards compat with upstream
287+
# renaming it to skill_id would be more accurate
288+
self.sched_id = sched_id or self.name
287289
self.bus = bus
288290
self.events = EventContainer(bus)
289-
290291
self.scheduled_repeats = []
291292

293+
@property
294+
def skill_id(self):
295+
# self.skill_id is preferred usage
296+
# self.sched_id can not be deprecated
297+
return self.sched_id
298+
292299
def set_bus(self, bus):
293300
self.bus = bus
294301
self.events.set_bus(bus)
295302

296303
def set_id(self, sched_id):
304+
# we can not rename the sched_id keyword argument
305+
# because of backwards compat with upstream
306+
# renaming it to skill_id would be more accurate
297307
self.sched_id = sched_id
298308

299309
def _create_unique_name(self, name):
@@ -306,7 +316,7 @@ def _create_unique_name(self, name):
306316
Returns:
307317
str: name unique to this skill
308318
"""
309-
return str(self.sched_id) + ':' + (name or '')
319+
return self.skill_id + ':' + (name or self.name)
310320

311321
def _schedule_event(self, handler, when, data, name,
312322
repeat_interval=None, context=None):
@@ -329,16 +339,15 @@ def _schedule_event(self, handler, when, data, name,
329339
if isinstance(when, (int, float)) and when >= 0:
330340
when = datetime.now() + timedelta(seconds=when)
331341
if not name:
332-
name = self.name + handler.__name__
342+
name = self.skill_id + handler.__name__
333343
unique_name = self._create_unique_name(name)
334344
if repeat_interval:
335345
self.scheduled_repeats.append(name) # store "friendly name"
336346

337347
data = data or {}
338348

339349
def on_error(e):
340-
LOG.exception('An error occurred executing the scheduled event '
341-
'{}'.format(repr(e)))
350+
LOG.exception(f'An error occurred executing the scheduled event {e}')
342351

343352
wrapped = create_basic_wrapper(handler, on_error)
344353
self.events.add(unique_name, wrapped, once=not repeat_interval)
@@ -347,7 +356,7 @@ def on_error(e):
347356
'repeat': repeat_interval,
348357
'data': data}
349358
context = context or {}
350-
context["skill_id"] = self.sched_id
359+
context["skill_id"] = self.skill_id
351360
self.bus.emit(Message('mycroft.scheduler.schedule_event',
352361
data=event_data, context=context))
353362

@@ -410,7 +419,7 @@ def update_scheduled_event(self, name, data=None):
410419
'data': data
411420
}
412421
self.bus.emit(Message('mycroft.schedule.update_event',
413-
data=data, context={"skill_id": self.sched_id}))
422+
data=data, context={"skill_id": self.skill_id}))
414423

415424
def cancel_scheduled_event(self, name):
416425
"""Cancel a pending event. The event will no longer be scheduled
@@ -426,7 +435,7 @@ def cancel_scheduled_event(self, name):
426435
if self.events.remove(unique_name):
427436
self.bus.emit(Message('mycroft.scheduler.remove_event',
428437
data=data,
429-
context={"skill_id": self.sched_id}))
438+
context={"skill_id": self.skill_id}))
430439

431440
def get_scheduled_event_status(self, name):
432441
"""Get scheduled event data and return the amount of time left
@@ -443,9 +452,9 @@ def get_scheduled_event_status(self, name):
443452
event_name = self._create_unique_name(name)
444453
data = {'name': event_name}
445454

446-
reply_name = 'mycroft.event_status.callback.{}'.format(event_name)
455+
reply_name = f'mycroft.event_status.callback.{event_name}'
447456
msg = Message('mycroft.scheduler.get_event', data=data,
448-
context={"skill_id": self.sched_id})
457+
context={"skill_id": self.skill_id})
449458
status = self.bus.wait_for_response(msg, reply_type=reply_name)
450459

451460
if status:

mycroft/skills/mycroft_skill/mycroft_skill.py

Lines changed: 32 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ def __init__(self, name=None, bus=None, use_settings=True, skill_id=""):
137137
self.gui = SkillGUI(self)
138138

139139
self._bus = None
140-
self._enclosure = None
140+
self._enclosure = EnclosureAPI(bus)
141141

142142
#: Mycroft global configuration. (dict)
143143
self.config_core = Configuration.get()
@@ -163,14 +163,14 @@ def __init__(self, name=None, bus=None, use_settings=True, skill_id=""):
163163
# fully initialized when self.skill_id is set
164164
self.file_system = FileSystemAccess(get_temp_path(self.name))
165165

166-
self.log = LOG.create_logger(self.name) #: Skill logger instance
166+
self.log = LOG
167167
self.reload_skill = True #: allow reloading (default True)
168168

169169
self.events = EventContainer(bus)
170170
self.voc_match_cache = {}
171171

172172
# Delegator classes
173-
self.event_scheduler = EventSchedulerInterface(self.name)
173+
self.event_scheduler = EventSchedulerInterface()
174174
self.intent_service = IntentServiceInterface()
175175

176176
# Skill Public API
@@ -207,6 +207,10 @@ def _startup(self, bus, skill_id=""):
207207
self.skill_id = skill_id or basename(self.root_dir)
208208
self._init_settings()
209209
self._init_filesystem()
210+
self.log = LOG.create_logger(self.skill_id) #: Skill logger instance
211+
self.intent_service.set_id(self.skill_id)
212+
self.event_scheduler.set_id(self.skill_id)
213+
self.enclosure.set_id(self.skill_id)
210214

211215
# initialize anything that depends on the messagebus
212216
self.bind(bus)
@@ -266,8 +270,7 @@ def _init_settings(self):
266270
self._initial_settings = copy(self.settings)
267271

268272
def _init_filesystem(self):
269-
# TODO start using self.skill_id instead of self.name
270-
skill_file_system = FileSystemAccess(join('skills', self.name))
273+
skill_file_system = FileSystemAccess(join('skills', self.skill_id))
271274
if not isdir(skill_file_system.path):
272275
shutil.move(self.file_system.path, skill_file_system.path)
273276
else:
@@ -421,10 +424,8 @@ def bind(self, bus):
421424
self._bus = bus
422425
self.events.set_bus(bus)
423426
self.intent_service.set_bus(bus)
424-
self.intent_service.set_id(self.skill_id)
425427
self.event_scheduler.set_bus(bus)
426-
self.event_scheduler.set_id(self.skill_id)
427-
self._enclosure = EnclosureAPI(bus, self.name)
428+
self._enclosure.set_bus(bus)
428429
self._register_system_event_handlers()
429430
# Initialize the SkillGui
430431
self.gui.setup_default_handlers()
@@ -460,14 +461,13 @@ def wrapper(message):
460461
name = method.__name__
461462
self.public_api[name] = {
462463
'help': doc,
463-
'type': '{}.{}'.format(self.skill_id, name),
464+
'type': f'{self.skill_id}.{name}',
464465
'func': method
465466
}
466467
for key in self.public_api:
467468
if ('type' in self.public_api[key] and
468469
'func' in self.public_api[key]):
469-
LOG.debug('Adding api method: '
470-
'{}'.format(self.public_api[key]['type']))
470+
LOG.debug(f"Adding api method: {self.public_api[key]['type']}")
471471

472472
# remove the function member since it shouldn't be
473473
# reused and can't be sent over the messagebus
@@ -476,7 +476,7 @@ def wrapper(message):
476476
wrap_method(func))
477477

478478
if self.public_api:
479-
self.add_event('{}.public_api'.format(self.skill_id),
479+
self.add_event(f'{self.skill_id}.public_api',
480480
self._send_public_api)
481481

482482
@property
@@ -518,15 +518,15 @@ def handle_settings_change(self, message):
518518
if self.settings_meta:
519519
remote_settings = message.data.get(self.settings_meta.skill_gid)
520520
if remote_settings is not None:
521-
LOG.info('Updating settings for skill ' + self.name)
521+
LOG.info('Updating settings for skill ' + self.skill_id)
522522
self.settings.update(**remote_settings)
523523
self.settings.store()
524524
if self.settings_change_callback is not None:
525525
self.settings_change_callback()
526526

527527
def detach(self):
528528
for (name, _) in self.intent_service:
529-
name = '{}:{}'.format(self.skill_id, name)
529+
name = f'{self.skill_id}:{name}'
530530
self.intent_service.detach_intent(name)
531531

532532
def initialize(self):
@@ -584,7 +584,7 @@ def activate(self):
584584
if "skill_id" not in msg.context:
585585
msg.context["skill_id"] = self.skill_id
586586
self.bus.emit(msg.forward("intent.service.skills.activate",
587-
data={"skill_id": self.skill_id}))
587+
{"skill_id": self.skill_id}))
588588

589589
def deactivate(self):
590590
"""remove skill from active_skill list in intent_service.
@@ -594,7 +594,7 @@ def deactivate(self):
594594
if "skill_id" not in msg.context:
595595
msg.context["skill_id"] = self.skill_id
596596
self.bus.emit(msg.forward(f"intent.service.skills.deactivate",
597-
data={"skill_id": self.skill_id}))
597+
{"skill_id": self.skill_id}))
598598

599599
def handle_converse_ack(self, message):
600600
self.bus.emit(message.reply(
@@ -842,11 +842,8 @@ def ask_selection(self, options, dialog='',
842842

843843
if numeric:
844844
for idx, opt in enumerate(options):
845-
opt_str = "{number}, {option_text}".format(
846-
number=pronounce_number(
847-
idx + 1, self.lang), option_text=opt)
848-
849-
self.speak(opt_str, wait=True)
845+
number = pronounce_number(idx + 1, self.lang)
846+
self.speak(f"{number}, {opt}", wait=True)
850847
else:
851848
opt_str = join_list(options, "or", lang=self.lang) + "?"
852849
self.speak(opt_str, wait=True)
@@ -899,8 +896,7 @@ def voc_match(self, utt, voc_filename, lang=None, exact=False):
899896
voc_filename + '.voc'))
900897

901898
if not voc or not exists(voc):
902-
raise FileNotFoundError(
903-
'Could not find {}.voc file'.format(voc_filename))
899+
raise FileNotFoundError(f'Could not find {voc_filename}.voc file')
904900
# load vocab and flatten into a simple list
905901
vocab = read_vocab_file(voc)
906902
self.voc_match_cache[cache_key] = list(chain(*vocab))
@@ -923,7 +919,7 @@ def report_metric(self, name, data):
923919
name (str): Name of metric. Must use only letters and hyphens
924920
data (dict): JSON dictionary to report. Must be valid JSON
925921
"""
926-
report_metric('{}:{}'.format(basename(self.root_dir), name), data)
922+
report_metric(f'{self.skill_id}:{name}', data)
927923

928924
def send_email(self, title, body):
929925
"""Send an email to the registered user's email.
@@ -970,12 +966,10 @@ def register_resting_screen(self):
970966
method = getattr(self, attr_name)
971967
if hasattr(method, 'resting_handler'):
972968
self.resting_name = method.resting_handler
973-
self.log.info('Registering resting screen {} for {}.'.format(
974-
method, self.resting_name))
969+
self.log.info(f'Registering resting screen {method} for {self.resting_name}.')
975970

976971
# Register for handling resting screen
977-
msg_type = '{}.{}'.format(self.skill_id, 'idle')
978-
self.add_event(msg_type, method)
972+
self.add_event(f'{self.skill_id}.idle', method)
979973
# Register handler for resting screen collect message
980974
self.add_event('mycroft.mark2.collect_idle',
981975
self._handle_collect_resting)
@@ -1285,7 +1279,7 @@ def register_intent_file(self, intent_file, handler):
12851279
name = f'{self.skill_id}:{intent_file}'
12861280
filename = self.find_resource(intent_file, 'vocab', lang=lang)
12871281
if not filename:
1288-
self.log.error('Unable to find "{}"'.format(intent_file))
1282+
self.log.error(f'Unable to find "{intent_file}"')
12891283
continue
12901284
self.intent_service.register_padatious_intent(name, filename, lang)
12911285
if handler:
@@ -1317,7 +1311,7 @@ def register_entity_file(self, entity_file):
13171311
if not filename:
13181312
self.log.error(f'Unable to find "{entity_file}"')
13191313
continue
1320-
name = '{}:{}'.format(self.skill_id, entity_file)
1314+
name = f'{self.skill_id}:{entity_file}'
13211315
self.intent_service.register_padatious_entity(name, filename, lang)
13221316

13231317
def handle_enable_intent(self, message):
@@ -1356,8 +1350,7 @@ def disable_intent(self, intent_name):
13561350
self.intent_service.detach_intent(lang_intent_name)
13571351
return True
13581352
else:
1359-
LOG.error('Could not disable '
1360-
'{}, it hasn\'t been registered.'.format(intent_name))
1353+
LOG.error(f'Could not disable {intent_name}, it hasn\'t been registered.')
13611354
return False
13621355

13631356
def enable_intent(self, intent_name):
@@ -1376,11 +1369,10 @@ def enable_intent(self, intent_name):
13761369
else:
13771370
intent.name = intent_name
13781371
self.register_intent(intent, None)
1379-
LOG.debug('Enabling intent {}'.format(intent_name))
1372+
LOG.debug(f'Enabling intent {intent_name}')
13801373
return True
13811374
else:
1382-
LOG.error('Could not enable '
1383-
'{}, it hasn\'t been registered.'.format(intent_name))
1375+
LOG.error(f'Could not enable {intent_name}, it hasn\'t been registered.')
13841376
return False
13851377

13861378
def set_context(self, context, word='', origin=''):
@@ -1477,8 +1469,8 @@ def speak(self, utterance, expect_response=False, wait=False, meta=None):
14771469
"""
14781470
# registers the skill as being active
14791471
meta = meta or {}
1480-
meta['skill'] = self.name
1481-
self.enclosure.register(self.name)
1472+
meta['skill'] = self.skill_id
1473+
self.enclosure.register(self.skill_id)
14821474
data = {'utterance': utterance,
14831475
'expect_response': expect_response,
14841476
'meta': meta,
@@ -1637,7 +1629,7 @@ def __handle_stop(self, message):
16371629
{"skill_id": self.skill_id}))
16381630
except Exception as e:
16391631
LOG.exception(e)
1640-
LOG.error(f'Failed to stop skill: {self.name}')
1632+
LOG.error(f'Failed to stop skill: {self.skill_id}')
16411633

16421634
def stop(self):
16431635
"""Optional method implemented by subclass."""
@@ -1675,14 +1667,12 @@ def default_shutdown(self):
16751667
try:
16761668
self.stop()
16771669
except Exception:
1678-
LOG.error('Failed to stop skill: {}'.format(self.name),
1679-
exc_info=True)
1670+
LOG.error(f'Failed to stop skill: {self.skill_id}', exc_info=True)
16801671

16811672
try:
16821673
self.shutdown()
16831674
except Exception as e:
1684-
LOG.error('Skill specific shutdown function encountered '
1685-
'an error: {}'.format(repr(e)))
1675+
LOG.error(f'Skill specific shutdown function encountered an error: {e}')
16861676

16871677
self.bus.emit(
16881678
Message('detach_skill', {'skill_id': str(self.skill_id) + ':'},

0 commit comments

Comments
 (0)