Skip to content

Commit

Permalink
feat/compat_handler_decorator
Browse files Browse the repository at this point in the history
add a decorator to specify backwards compatible alternate handlers for specific ovos/mycroft versions
  • Loading branch information
JarbasAl committed Sep 21, 2023
1 parent 8610f31 commit 3771b4b
Show file tree
Hide file tree
Showing 5 changed files with 161 additions and 127 deletions.
43 changes: 43 additions & 0 deletions ovos_workshop/decorators/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,49 @@
from ovos_utils import classproperty


def backwards_compat(classic_core=None, pre_007=None, no_core=None):
"""
Decorator to run a different method if specific ovos-core versions are detected
"""

def backwards_compat_decorator(func):
is_classic = False
is_old = False
is_standalone = True
try:
from mycroft.version import CORE_VERSION_STR # all classic mycroft and ovos versions
is_classic = True
is_standalone = False

try:
from ovos_core.version import OVOS_VERSION_MINOR # ovos-core >= 0.0.8
is_classic = False
except ImportError:
is_old = True
try:
from mycroft.version import OVOS_VERSION_MINOR # ovos-core <= 0.0.7
is_classic = False
except:
is_standalone = True

except:
is_standalone = True

@wraps(func)
def func_wrapper(*args, **kwargs):
if is_classic and callable(classic_core):
return classic_core(*args, **kwargs)
if is_old and callable(pre_007):
return pre_007(*args, **kwargs)
if is_standalone and callable(no_core):
return no_core(*args, **kwargs)
return func(*args, **kwargs)

return func_wrapper

return backwards_compat_decorator


def adds_context(context: str, words: str = ''):
"""
Decorator to add context to the Adapt context manager.
Expand Down
50 changes: 21 additions & 29 deletions ovos_workshop/skills/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
from ovos_utils.sound import play_acknowledge_sound
from ovos_utils import classproperty

from ovos_workshop.decorators import backwards_compat
from ovos_workshop.decorators.killable import AbortEvent
from ovos_workshop.decorators.killable import killable_event, \
AbortQuestion
Expand All @@ -73,23 +74,6 @@ def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)


def is_classic_core() -> bool:
"""
Check if the current core is the classic mycroft-core
"""
try:
from mycroft.version import OVOS_VERSION_STR
return False # ovos-core
except ImportError:
try:
log_deprecation("Support for `mycroft_core` will be deprecated",
"0.1.0")
from mycroft.version import CORE_VERSION_STR
return True # mycroft-core
except ImportError:
return False # standalone


def simple_trace(stack_trace: List[str]) -> str:
"""
Generate a simplified traceback.
Expand Down Expand Up @@ -713,6 +697,26 @@ def _load_lang(self, root_directory: Optional[str] = None,
skill_id=self.skill_id)
return self._lang_resources[lang]

def __bind_classic(self, bus):
self._bus = bus
self.events.set_bus(bus)
self.intent_service.set_bus(bus)
self.event_scheduler.set_bus(bus)
self._enclosure.set_bus(bus)
self._register_system_event_handlers()
self._register_public_api()
log_deprecation("Support for mycroft-core is deprecated",
"0.1.0")
# inject ovos exclusive features in vanilla mycroft-core
# if possible
# limited support for missing skill deactivated event
# TODO - update ConverseTracker
ConverseTracker.connect_bus(self.bus) # pull/1468
self.add_event("converse.skill.deactivated",
self._handle_skill_deactivated,
speak_errors=False)

@backwards_compat(classic_core=__bind_classic)
def bind(self, bus: MessageBusClient):
"""
Register MessageBusClient with skill.
Expand All @@ -727,18 +731,6 @@ def bind(self, bus: MessageBusClient):
self._register_system_event_handlers()
self._register_public_api()

if is_classic_core():
log_deprecation("Support for mycroft-core is deprecated",
"0.1.0")
# inject ovos exclusive features in vanilla mycroft-core
# if possible
# limited support for missing skill deactivated event
# TODO - update ConverseTracker
ConverseTracker.connect_bus(self.bus) # pull/1468
self.add_event("converse.skill.deactivated",
self._handle_skill_deactivated,
speak_errors=False)

def _register_public_api(self):
"""
Find and register API methods decorated with `@api_method` and create a
Expand Down
27 changes: 13 additions & 14 deletions ovos_workshop/skills/common_query_skill.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
from ovos_utils.file_utils import resolve_resource_file
from ovos_utils.log import LOG
from ovos_workshop.skills.ovos import OVOSSkill, is_classic_core
from ovos_workshop.decorators import backwards_compat


class CQSMatchLevel(IntEnum):
Expand Down Expand Up @@ -187,6 +188,17 @@ def __calc_confidence(self, match, phrase, level, answer):

return confidence

def __handle_query_classic(self, message):
"""does not perform self.speak, < 0.0.8 this is done by core itself"""
if message.data["skill_id"] != self.skill_id:
# Not for this skill!
return
phrase = message.data["phrase"]
data = message.data.get("callback_data") or {}
# Invoke derived class to provide playback data
self.CQS_action(phrase, data)

@backwards_compat(classic_core=__handle_query_classic, pre_007=__handle_query_classic)
def __handle_query_action(self, message):
"""Message handler for question:action.
Expand All @@ -199,20 +211,7 @@ def __handle_query_action(self, message):
phrase = message.data["phrase"]
data = message.data.get("callback_data") or {}
if data.get("answer"):
# check core version, ovos-core does this speak call itself up to version 0.0.8a4
core_speak = is_classic_core()
if not core_speak:
try:
from mycroft.version import OVOS_VERSION_MAJOR, OVOS_VERSION_MINOR, OVOS_VERSION_BUILD, OVOS_VERSIOM_ALPHA
if OVOS_VERSION_MAJOR == 0 and OVOS_VERSION_MINOR == 0 and OVOS_VERSION_BUILD < 8:
core_speak = True
elif OVOS_VERSION_MAJOR == 0 and OVOS_VERSION_MINOR == 0 and OVOS_VERSION_BUILD == 8 and \
OVOS_VERSIOM_ALPHA < 5:
core_speak = True
except ImportError:
pass
if not core_speak:
self.speak(data["answer"])
self.speak(data["answer"])
# Invoke derived class to provide playback data
self.CQS_action(phrase, data)

Expand Down
40 changes: 18 additions & 22 deletions ovos_workshop/skills/fallback.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,16 @@
import operator
from typing import Optional, List, Callable, Tuple

from ovos_config import Configuration

from ovos_bus_client import MessageBusClient
from ovos_utils.log import LOG
from ovos_utils.messagebus import get_handler_name, Message
from ovos_utils.metrics import Stopwatch
from ovos_utils.skills import get_non_properties
from ovos_config import Configuration
from ovos_workshop.decorators import backwards_compat
from ovos_workshop.permissions import FallbackMode
from ovos_workshop.skills.ovos import OVOSSkill, is_classic_core
from ovos_workshop.skills.ovos import OVOSSkill


class _MutableFallback(type(OVOSSkill)):
Expand Down Expand Up @@ -59,31 +61,25 @@ class FallbackSkill(_MetaFB, metaclass=_MutableFallback):
A Fallback can either observe or consume an utterance. A consumed
utterance will not be seen by any other Fallback handlers.
"""

@staticmethod
def __get_bases_classic():
LOG.debug("Using V1 Fallback")
return (FallbackSkillV1, FallbackSkill, _MetaFB)

@backwards_compat(classic_core=__get_bases_classic,
pre_007=__get_bases_classic)
@staticmethod
def __get_bases():
LOG.debug("Using V2 Fallback")
return (FallbackSkillV2, FallbackSkill, _MetaFB)

def __new__(cls, *args, **kwargs):
if cls is FallbackSkill:
# direct instantiation of class, dynamic wizardry or unittests
# return V2 as expected, V1 will eventually be dropped
return FallbackSkillV2(*args, **kwargs)

is_old = is_classic_core()
if not is_old:
try:
from mycroft.version import OVOS_VERSION_MAJOR, \
OVOS_VERSION_MINOR, OVOS_VERSION_BUILD, OVOS_VERSION_ALPHA
if OVOS_VERSION_MAJOR == 0 and OVOS_VERSION_MINOR == 0 and \
OVOS_VERSION_BUILD < 8:
is_old = True
elif OVOS_VERSION_MAJOR == 0 and OVOS_VERSION_MINOR == 0 and \
OVOS_VERSION_BUILD == 8 and 0 < OVOS_VERSION_ALPHA < 5:
is_old = True
except ImportError:
pass
if is_old:
LOG.debug("Using V1 Fallback")
cls.__bases__ = (FallbackSkillV1, FallbackSkill, _MetaFB)
else:
LOG.debug("Using V2 Fallback")
cls.__bases__ = (FallbackSkillV2, FallbackSkill, _MetaFB)
cls.__bases__ = cls.__get_bases()
return super().__new__(cls, *args, **kwargs)

@classmethod
Expand Down
Loading

0 comments on commit 3771b4b

Please sign in to comment.