Skip to content

Commit

Permalink
Add docstrings and unit tests for app.py (#110)
Browse files Browse the repository at this point in the history
  • Loading branch information
NeonDaniel authored Jul 10, 2023
1 parent cb973a1 commit 5b56a11
Show file tree
Hide file tree
Showing 2 changed files with 72 additions and 17 deletions.
66 changes: 49 additions & 17 deletions ovos_workshop/app.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,33 @@
from os.path import isdir, join

from typing import Optional
from ovos_config.locations import get_xdg_config_save_path
from ovos_utils.messagebus import get_mycroft_bus
from ovos_utils.log import LOG

from ovos_utils.log import log_deprecation
from ovos_utils.gui import GUIInterface
from ovos_bus_client.client.client import MessageBusClient
from ovos_workshop.resource_files import locate_lang_directories
from ovos_workshop.skills.ovos import OVOSSkill


class OVOSAbstractApplication(OVOSSkill):
def __init__(self, skill_id, bus=None, resources_dir=None,
lang=None, settings=None, gui=None, enable_settings_manager=False):
def __init__(self, skill_id: str, bus: Optional[MessageBusClient] = None,
resources_dir: Optional[str] = None,
lang=None, settings: Optional[dict] = None,
gui: Optional[GUIInterface] = None,
enable_settings_manager: bool = False):
"""
Create an Application. An application is essentially a skill, but
designed such that it may be run without an intent service.
@param skill_id: Unique ID for this application
@param bus: MessageBusClient to bind to application
@param resources_dir: optional root resource directory (else defaults to
application `root_dir`
@param lang: DEPRECATED language of the application
@param settings: DEPRECATED settings object
@param gui: GUIInterface to bind (if `None`, one is created)
@param enable_settings_manager: if True, enables a SettingsManager for
this application to manage default settings and backend sync
"""
super().__init__(bus=bus, gui=gui, resources_dir=resources_dir,
enable_settings_manager=enable_settings_manager)
self.skill_id = skill_id
Expand All @@ -22,25 +39,38 @@ def __init__(self, skill_id, bus=None, resources_dir=None,
bus = get_mycroft_bus()
self._startup(bus, skill_id)
if settings:
LOG.warning("settings arg is deprecated and will be removed "
"in a future release")
log_deprecation(f"Settings should be set in {self._settings_path}. "
f"Passing `settings` to __init__ is not supported.",
"0.1.0")
self.settings.merge(settings)

@property
def _settings_path(self):
def _settings_path(self) -> str:
"""
Overrides the default path to put settings in `apps` subdirectory.
"""
return join(get_xdg_config_save_path(), 'apps', self.skill_id,
'settings.json')

def default_shutdown(self):
"""
Shutdown this application.
"""
self.clear_intents()
super().default_shutdown()
if self._dedicated_bus:
self.bus.close()

def get_language_dir(self, base_path=None, lang=None):
""" checks for all language variations and returns best path
eg, if lang is set to pt-pt but only pt-br resources exist,
those will be loaded instead of failing, or en-gb vs en-us and so on
def get_language_dir(self, base_path: Optional[str] = None,
lang: Optional[str] = None) -> Optional[str]:
"""
Get the best matched language resource directory for the requested lang.
This will consider dialects for the requested language, i.e. if lang is
set to pt-pt but only pt-br resources exist, the `pt-br` resource path
will be returned.
@param base_path: root path to find resources (default res_dir)
@param lang: language to get resources for (default self.lang)
@return: path to language resources if they exist, else None
"""

base_path = base_path or self.res_dir
Expand All @@ -56,13 +86,15 @@ def get_language_dir(self, base_path=None, lang=None):
similar_dialect_directories = locate_lang_directories(lang, base_path)
for directory in similar_dialect_directories:
if directory.exists():
return directory
return str(directory)

def clear_intents(self):
# remove bus handlers, otherwise if re-registered we get multiple
# handler executions
"""
Remove bus event handlers and detach from the intent service to prevent
multiple registered handlers.
"""
for intent_name, _ in self.intent_service:
event_name = f'{self.skill_id}:{intent_name}'
self.remove_event(event_name)

self.intent_service.detach_all() # delete old intents before re-registering
# delete old intents before re-registering
self.intent_service.detach_all()
23 changes: 23 additions & 0 deletions test/unittests/test_abstract_app.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

from os.path import join, dirname
from os import remove
from unittest.mock import Mock, patch

from ovos_utils.gui import GUIInterface
from ovos_utils.messagebus import FakeBus
Expand Down Expand Up @@ -84,6 +85,28 @@ def test_settings_path(self):
remove(test_app._settings_path)
remove(test_skill._settings_path)

@patch("ovos_workshop.app.OVOSSkill.default_shutdown")
def test_default_shutdown(self, skill_shutdown):
real_clear_intents = self.app.clear_intents
real_bus_close = self.app.bus.close
self.app.bus.close = Mock()
self.app.clear_intents = Mock()
self.app.default_shutdown()
self.app.clear_intents.assert_called_once()
self.app.bus.close.assert_called_once()
skill_shutdown.assert_called_once()

self.app.bus.close = real_bus_close
self.app.clear_intents = real_clear_intents

def test_get_language_dir(self):
# TODO
pass

def test_clear_intents(self):
# TODO
pass

def test_class_inheritance(self):
from ovos_workshop.skills.base import BaseSkill
from ovos_workshop.skills.ovos import OVOSSkill
Expand Down

0 comments on commit 5b56a11

Please sign in to comment.