From 9ca2018dfded681e286e8c3c41beb781ec349ddf Mon Sep 17 00:00:00 2001
From: NeonJarbas <59943014+NeonJarbas@users.noreply.github.com>
Date: Thu, 2 Jun 2022 16:32:00 +0100
Subject: [PATCH] Fix/decouple from mycroft (#21)

* fix/do not require mycroft

* fix/decouple_decorators_from_skills

being in the skills module was causing cyclic imports due to helper skill classes importing mycroft

* build tests

Co-authored-by: jarbasai <jarbasai@mailfence.com>
---
 .github/workflows/build_tests.yml             |   2 -
 ovos_workshop/__init__.py                     |   4 +-
 ovos_workshop/app.py                          |   4 +-
 ovos_workshop/decorators/__init__.py          |  22 +++
 ovos_workshop/decorators/converse.py          |  11 ++
 ovos_workshop/decorators/fallback_handler.py  |   8 ++
 ovos_workshop/decorators/killable.py          |  80 +++++++++++
 ovos_workshop/decorators/layers.py            | 130 +++++++++++++++++
 ovos_workshop/decorators/ocp.py               | 102 ++++++++++++++
 ovos_workshop/skills/__init__.py              |  12 +-
 ovos_workshop/skills/common_play.py           |   2 +-
 ovos_workshop/skills/decorators/__init__.py   |  24 +---
 ovos_workshop/skills/decorators/converse.py   |  13 +-
 .../skills/decorators/fallback_handler.py     |  10 +-
 ovos_workshop/skills/decorators/killable.py   |  82 +----------
 ovos_workshop/skills/decorators/layers.py     | 132 +-----------------
 ovos_workshop/skills/decorators/ocp.py        | 104 +-------------
 ovos_workshop/skills/ovos.py                  |   2 +-
 18 files changed, 378 insertions(+), 366 deletions(-)
 create mode 100644 ovos_workshop/decorators/__init__.py
 create mode 100644 ovos_workshop/decorators/converse.py
 create mode 100644 ovos_workshop/decorators/fallback_handler.py
 create mode 100644 ovos_workshop/decorators/killable.py
 create mode 100644 ovos_workshop/decorators/layers.py
 create mode 100644 ovos_workshop/decorators/ocp.py

diff --git a/.github/workflows/build_tests.yml b/.github/workflows/build_tests.yml
index 14562cf3..9ce0fbd3 100644
--- a/.github/workflows/build_tests.yml
+++ b/.github/workflows/build_tests.yml
@@ -24,8 +24,6 @@ jobs:
     runs-on: ubuntu-latest
     steps:
       - uses: actions/checkout@v2
-        with:
-          ref: ${{ github.head_ref }}
       - name: Setup Python
         uses: actions/setup-python@v1
         with:
diff --git a/ovos_workshop/__init__.py b/ovos_workshop/__init__.py
index 02e23ebe..cc71fb9d 100644
--- a/ovos_workshop/__init__.py
+++ b/ovos_workshop/__init__.py
@@ -1,5 +1,5 @@
 from ovos_workshop.app import OVOSAbstractApplication
-from ovos_workshop.skills.decorators import *
-from ovos_workshop.skills.decorators.killable import killable_event, \
+from ovos_workshop.decorators import *
+from ovos_workshop.decorators.killable import killable_event, \
     AbortEvent, AbortQuestion
 from ovos_workshop.skills.layers import IntentLayers
diff --git a/ovos_workshop/app.py b/ovos_workshop/app.py
index 40103564..ac53e9be 100644
--- a/ovos_workshop/app.py
+++ b/ovos_workshop/app.py
@@ -25,8 +25,8 @@
 
 from ovos_utils.skills import get_non_properties
 from ovos_utils.intents import IntentBuilder, Intent, AdaptIntent
-from ovos_workshop.skills.decorators import *
-from ovos_workshop.skills.decorators.killable import killable_event, \
+from ovos_workshop.decorators import *
+from ovos_workshop.decorators.killable import killable_event, \
     AbortEvent, AbortQuestion
 from ovos_workshop.skills.layers import IntentLayers
 
diff --git a/ovos_workshop/decorators/__init__.py b/ovos_workshop/decorators/__init__.py
new file mode 100644
index 00000000..aff36485
--- /dev/null
+++ b/ovos_workshop/decorators/__init__.py
@@ -0,0 +1,22 @@
+from ovos_workshop.decorators.killable import \
+    killable_intent, killable_event
+from ovos_workshop.decorators.layers import enables_layer, \
+    disables_layer, layer_intent, removes_layer, resets_layers, replaces_layer
+from ovos_workshop.decorators.converse import converse_handler
+from ovos_workshop.decorators.fallback_handler import fallback_handler
+
+
+def resting_screen_handler(name):
+    """Decorator for adding a method as an resting screen handler.
+
+    If selected will be shown on screen when device enters idle mode.
+    """
+
+    def real_decorator(func):
+        # Store the resting information inside the function
+        # This will be used later in register_resting_screen
+        if not hasattr(func, 'resting_handler'):
+            func.resting_handler = name
+        return func
+
+    return real_decorator
diff --git a/ovos_workshop/decorators/converse.py b/ovos_workshop/decorators/converse.py
new file mode 100644
index 00000000..126761d7
--- /dev/null
+++ b/ovos_workshop/decorators/converse.py
@@ -0,0 +1,11 @@
+
+
+def converse_handler():
+    """Decorator for aliasing a method as the converse method"""
+
+    def real_decorator(func):
+        if not hasattr(func, 'converse'):
+            func.converse = True
+        return func
+
+    return real_decorator
diff --git a/ovos_workshop/decorators/fallback_handler.py b/ovos_workshop/decorators/fallback_handler.py
new file mode 100644
index 00000000..56b79c49
--- /dev/null
+++ b/ovos_workshop/decorators/fallback_handler.py
@@ -0,0 +1,8 @@
+
+def fallback_handler(priority=50):
+    def real_decorator(func):
+        if not hasattr(func, 'fallback_priority'):
+            func.fallback_priority = priority
+        return func
+
+    return real_decorator
diff --git a/ovos_workshop/decorators/killable.py b/ovos_workshop/decorators/killable.py
new file mode 100644
index 00000000..03ab827b
--- /dev/null
+++ b/ovos_workshop/decorators/killable.py
@@ -0,0 +1,80 @@
+import time
+from ovos_utils import create_killable_daemon
+from ovos_utils.messagebus import Message
+import threading
+from inspect import signature
+from functools import wraps
+
+
+class AbortEvent(StopIteration):
+    """ abort bus event handler """
+
+
+class AbortIntent(AbortEvent):
+    """ abort intent parsing """
+
+
+class AbortQuestion(AbortEvent):
+    """ gracefully abort get_response queries """
+
+
+def killable_intent(msg="mycroft.skills.abort_execution",
+                    callback=None, react_to_stop=True, call_stop=True,
+                    stop_tts=True):
+    return killable_event(msg, AbortIntent, callback, react_to_stop,
+                          call_stop, stop_tts)
+
+
+def killable_event(msg="mycroft.skills.abort_execution", exc=AbortEvent,
+                   callback=None, react_to_stop=False, call_stop=False,
+                   stop_tts=False):
+    # Begin wrapper
+    def create_killable(func):
+
+        @wraps(func)
+        def call_function(*args, **kwargs):
+            skill = args[0]
+            t = create_killable_daemon(func, args, kwargs, autostart=False)
+
+            def abort(_):
+                if not t.is_alive():
+                    return
+                if stop_tts:
+                    skill.bus.emit(Message("mycroft.audio.speech.stop"))
+                if call_stop:
+                    # call stop on parent skill
+                    skill.stop()
+
+                # ensure no orphan get_response daemons
+                # this is the only killable daemon that core itself will
+                # create, users should also account for this condition with
+                # callbacks if using the decorator for other purposes
+                skill._handle_killed_wait_response()
+
+                try:
+                    while t.is_alive():
+                        t.raise_exc(exc)
+                        time.sleep(0.1)
+                except threading.ThreadError:
+                    pass  # already killed
+                except AssertionError:
+                    pass  # could not determine thread id ?
+                if callback is not None:
+                    if len(signature(callback).parameters) == 1:
+                        # class method, needs self
+                        callback(args[0])
+                    else:
+                        callback()
+
+            # save reference to threads so they can be killed later
+            skill._threads.append(t)
+            skill.bus.once(msg, abort)
+            if react_to_stop:
+                skill.bus.once(args[0].skill_id + ".stop", abort)
+            t.start()
+            return t
+
+        return call_function
+
+    return create_killable
+
diff --git a/ovos_workshop/decorators/layers.py b/ovos_workshop/decorators/layers.py
new file mode 100644
index 00000000..5d1679c8
--- /dev/null
+++ b/ovos_workshop/decorators/layers.py
@@ -0,0 +1,130 @@
+import inspect
+from functools import wraps
+
+from ovos_workshop.skills.layers import IntentLayers
+
+
+def dig_for_skill(max_records: int = 10):
+    from ovos_workshop.app import OVOSAbstractApplication
+    from ovos_workshop.skills import MycroftSkill
+    stack = inspect.stack()[1:]  # First frame will be this function call
+    stack = stack if len(stack) <= max_records else stack[:max_records]
+    for record in stack:
+        args = inspect.getargvalues(record.frame)
+        if args.locals.get("self"):
+            obj = args.locals["self"]
+            if isinstance(obj, MycroftSkill) or \
+                    isinstance(obj, OVOSAbstractApplication):
+                return obj
+        elif args.locals.get("args"):
+            for obj in args.locals["args"]:
+                if isinstance(obj, MycroftSkill) or \
+                        isinstance(obj, OVOSAbstractApplication):
+                    return obj
+    return None
+
+
+def enables_layer(layer_name):
+    def layer_handler(func):
+        @wraps(func)
+        def call_function(*args, **kwargs):
+            skill = dig_for_skill()
+            skill.intent_layers = skill.intent_layers or \
+                                  IntentLayers().bind(skill)
+            func(*args, **kwargs)
+            skill.intent_layers.activate_layer(layer_name)
+
+        return call_function
+
+    return layer_handler
+
+
+def disables_layer(layer_name):
+    def layer_handler(func):
+        @wraps(func)
+        def call_function(*args, **kwargs):
+            skill = dig_for_skill()
+            skill.intent_layers = skill.intent_layers or \
+                                  IntentLayers().bind(skill)
+            func(*args, **kwargs)
+            skill.intent_layers.deactivate_layer(layer_name)
+
+        return call_function
+
+    return layer_handler
+
+
+def replaces_layer(layer_name, intent_list):
+    def layer_handler(func):
+        @wraps(func)
+        def call_function(*args, **kwargs):
+            skill = dig_for_skill()
+            skill.intent_layers = skill.intent_layers or \
+                                  IntentLayers().bind(skill)
+            func(*args, **kwargs)
+            skill.intent_layers.replace_layer(layer_name, intent_list)
+
+        return call_function
+
+    return layer_handler
+
+
+def removes_layer(layer_name, intent_list):
+    def layer_handler(func):
+        @wraps(func)
+        def call_function(*args, **kwargs):
+            skill = dig_for_skill()
+            skill.intent_layers = skill.intent_layers or \
+                                  IntentLayers().bind(skill)
+            func(*args, **kwargs)
+            skill.intent_layers.replace_layer(layer_name, intent_list)
+
+        return call_function
+
+    return layer_handler
+
+
+def resets_layers():
+    def layer_handler(func):
+        @wraps(func)
+        def call_function(*args, **kwargs):
+            skill = dig_for_skill()
+            skill.intent_layers = skill.intent_layers or \
+                                  IntentLayers().bind(skill)
+            func(*args, **kwargs)
+            skill.intent_layers.disable()
+
+        return call_function
+
+    return layer_handler
+
+
+def layer_intent(intent_parser, layer_name):
+    """Decorator for adding a method as an intent handler belonging to an
+    intent layer."""
+
+    def real_decorator(func):
+        # Store the intent_parser inside the function
+        # This will be used later to call register_intent
+        if not hasattr(func, 'intents'):
+            func.intents = []
+        if not hasattr(func, 'intent_layers'):
+            func.intent_layers = {}
+
+        func.intents.append(intent_parser)
+        if layer_name not in func.intent_layers:
+            func.intent_layers[layer_name] = []
+
+        # get intent_name
+        if hasattr(intent_parser, "build"):
+            intent = intent_parser.build()
+            intent_name = intent.name or func.__name__
+        elif hasattr(intent_parser, "name"):
+            intent_name = intent_parser.name
+        else:
+            intent_name = intent_parser
+    
+        func.intent_layers[layer_name].append(intent_name)
+        return func
+
+    return real_decorator
diff --git a/ovos_workshop/decorators/ocp.py b/ovos_workshop/decorators/ocp.py
new file mode 100644
index 00000000..0c91a3eb
--- /dev/null
+++ b/ovos_workshop/decorators/ocp.py
@@ -0,0 +1,102 @@
+from functools import wraps
+from ovos_workshop.skills.layers import IntentLayers
+from ovos_plugin_common_play.ocp import *
+from ovos_plugin_common_play.ocp.status import *
+
+
+def ocp_search():
+    """Decorator for adding a method as an common play search handler."""
+
+    def real_decorator(func):
+        # Store the flag inside the function
+        # This will be used later to identify the method
+        if not hasattr(func, 'is_ocp_search_handler'):
+            func.is_ocp_search_handler = True
+
+        return func
+
+    return real_decorator
+
+
+def ocp_play():
+    """Decorator for adding a method as an common play search handler."""
+
+    def real_decorator(func):
+        # Store the flag inside the function
+        # This will be used later to identify the method
+        if not hasattr(func, 'is_ocp_playback_handler'):
+            func.is_ocp_playback_handler = True
+
+        return func
+
+    return real_decorator
+
+
+def ocp_previous():
+    """Decorator for adding a method as an common play prev handler."""
+
+    def real_decorator(func):
+        # Store the flag inside the function
+        # This will be used later to identify the method
+        if not hasattr(func, 'is_ocp_prev_handler'):
+            func.is_ocp_prev_handler = True
+
+        return func
+
+    return real_decorator
+
+
+def ocp_next():
+    """Decorator for adding a method as an common play  next handler."""
+
+    def real_decorator(func):
+        # Store the flag inside the function
+        # This will be used later to identify the method
+        if not hasattr(func, 'is_ocp_next_handler'):
+            func.is_ocp_next_handler = True
+
+        return func
+
+    return real_decorator
+
+
+def ocp_pause():
+    """Decorator for adding a method as an common play pause handler."""
+
+    def real_decorator(func):
+        # Store the flag inside the function
+        # This will be used later to identify the method
+        if not hasattr(func, 'is_ocp_pause_handler'):
+            func.is_ocp_pause_handler = True
+
+        return func
+
+    return real_decorator
+
+
+def ocp_resume():
+    """Decorator for adding a method as an common play resume handler."""
+
+    def real_decorator(func):
+        # Store the flag inside the function
+        # This will be used later to identify the method
+        if not hasattr(func, 'is_ocp_resume_handler'):
+            func.is_ocp_resume_handler = True
+
+        return func
+
+    return real_decorator
+
+
+def ocp_featured_media():
+    """Decorator for adding a method as an common play search handler."""
+
+    def real_decorator(func):
+        # Store the flag inside the function
+        # This will be used later to identify the method
+        if not hasattr(func, 'is_ocp_featured_handler'):
+            func.is_ocp_featured_handler = True
+
+        return func
+
+    return real_decorator
diff --git a/ovos_workshop/skills/__init__.py b/ovos_workshop/skills/__init__.py
index 53e36fd0..470d0356 100644
--- a/ovos_workshop/skills/__init__.py
+++ b/ovos_workshop/skills/__init__.py
@@ -1,8 +1,10 @@
-import inspect
+try:
+    from ovos_workshop.skills.ovos import MycroftSkill, OVOSSkill,     OVOSFallbackSkill
+    from ovos_workshop.skills.idle_display_skill import IdleDisplaySkill
+except ImportError:
+    pass
+    # if mycroft is not available do not export the skill class
+    # this is common in OvosAbstractApp implementations such as OCP
 
-
-from ovos_workshop.skills.ovos import MycroftSkill, OVOSSkill, \
-    OVOSFallbackSkill
-from ovos_workshop.skills.idle_display_skill import IdleDisplaySkill
 from ovos_workshop.skills.layers import IntentLayers
 
diff --git a/ovos_workshop/skills/common_play.py b/ovos_workshop/skills/common_play.py
index 27761194..031d8300 100644
--- a/ovos_workshop/skills/common_play.py
+++ b/ovos_workshop/skills/common_play.py
@@ -1,6 +1,6 @@
 from inspect import signature
 from threading import Event
-from ovos_workshop.skills.decorators.ocp import *
+from ovos_workshop.decorators.ocp import *
 from ovos_workshop.skills.ovos import OVOSSkill, MycroftSkill
 from mycroft_bus_client import Message
 from ovos_utils.log import LOG
diff --git a/ovos_workshop/skills/decorators/__init__.py b/ovos_workshop/skills/decorators/__init__.py
index 1fd3c535..dc89c06d 100644
--- a/ovos_workshop/skills/decorators/__init__.py
+++ b/ovos_workshop/skills/decorators/__init__.py
@@ -1,22 +1,2 @@
-from ovos_workshop.skills.decorators.killable import \
-    killable_intent, killable_event
-from ovos_workshop.skills.decorators.layers import enables_layer, \
-    disables_layer, layer_intent, removes_layer, resets_layers, replaces_layer
-from ovos_workshop.skills.decorators.converse import converse_handler
-from ovos_workshop.skills.decorators.fallback_handler import fallback_handler
-
-
-def resting_screen_handler(name):
-    """Decorator for adding a method as an resting screen handler.
-
-    If selected will be shown on screen when device enters idle mode.
-    """
-
-    def real_decorator(func):
-        # Store the resting information inside the function
-        # This will be used later in register_resting_screen
-        if not hasattr(func, 'resting_handler'):
-            func.resting_handler = name
-        return func
-
-    return real_decorator
+from ovos_workshop.decorators import *
+# backwards compat import
diff --git a/ovos_workshop/skills/decorators/converse.py b/ovos_workshop/skills/decorators/converse.py
index 126761d7..1c994fe9 100644
--- a/ovos_workshop/skills/decorators/converse.py
+++ b/ovos_workshop/skills/decorators/converse.py
@@ -1,11 +1,2 @@
-
-
-def converse_handler():
-    """Decorator for aliasing a method as the converse method"""
-
-    def real_decorator(func):
-        if not hasattr(func, 'converse'):
-            func.converse = True
-        return func
-
-    return real_decorator
+from ovos_workshop.decorators.converse import *
+# backwards compat import
diff --git a/ovos_workshop/skills/decorators/fallback_handler.py b/ovos_workshop/skills/decorators/fallback_handler.py
index 56b79c49..acfcefdc 100644
--- a/ovos_workshop/skills/decorators/fallback_handler.py
+++ b/ovos_workshop/skills/decorators/fallback_handler.py
@@ -1,8 +1,2 @@
-
-def fallback_handler(priority=50):
-    def real_decorator(func):
-        if not hasattr(func, 'fallback_priority'):
-            func.fallback_priority = priority
-        return func
-
-    return real_decorator
+from ovos_workshop.decorators.fallback_handler import *
+# backwards compat import
diff --git a/ovos_workshop/skills/decorators/killable.py b/ovos_workshop/skills/decorators/killable.py
index 03ab827b..e25241f8 100644
--- a/ovos_workshop/skills/decorators/killable.py
+++ b/ovos_workshop/skills/decorators/killable.py
@@ -1,80 +1,2 @@
-import time
-from ovos_utils import create_killable_daemon
-from ovos_utils.messagebus import Message
-import threading
-from inspect import signature
-from functools import wraps
-
-
-class AbortEvent(StopIteration):
-    """ abort bus event handler """
-
-
-class AbortIntent(AbortEvent):
-    """ abort intent parsing """
-
-
-class AbortQuestion(AbortEvent):
-    """ gracefully abort get_response queries """
-
-
-def killable_intent(msg="mycroft.skills.abort_execution",
-                    callback=None, react_to_stop=True, call_stop=True,
-                    stop_tts=True):
-    return killable_event(msg, AbortIntent, callback, react_to_stop,
-                          call_stop, stop_tts)
-
-
-def killable_event(msg="mycroft.skills.abort_execution", exc=AbortEvent,
-                   callback=None, react_to_stop=False, call_stop=False,
-                   stop_tts=False):
-    # Begin wrapper
-    def create_killable(func):
-
-        @wraps(func)
-        def call_function(*args, **kwargs):
-            skill = args[0]
-            t = create_killable_daemon(func, args, kwargs, autostart=False)
-
-            def abort(_):
-                if not t.is_alive():
-                    return
-                if stop_tts:
-                    skill.bus.emit(Message("mycroft.audio.speech.stop"))
-                if call_stop:
-                    # call stop on parent skill
-                    skill.stop()
-
-                # ensure no orphan get_response daemons
-                # this is the only killable daemon that core itself will
-                # create, users should also account for this condition with
-                # callbacks if using the decorator for other purposes
-                skill._handle_killed_wait_response()
-
-                try:
-                    while t.is_alive():
-                        t.raise_exc(exc)
-                        time.sleep(0.1)
-                except threading.ThreadError:
-                    pass  # already killed
-                except AssertionError:
-                    pass  # could not determine thread id ?
-                if callback is not None:
-                    if len(signature(callback).parameters) == 1:
-                        # class method, needs self
-                        callback(args[0])
-                    else:
-                        callback()
-
-            # save reference to threads so they can be killed later
-            skill._threads.append(t)
-            skill.bus.once(msg, abort)
-            if react_to_stop:
-                skill.bus.once(args[0].skill_id + ".stop", abort)
-            t.start()
-            return t
-
-        return call_function
-
-    return create_killable
-
+from ovos_workshop.decorators.killable import *
+# backwards compat import
diff --git a/ovos_workshop/skills/decorators/layers.py b/ovos_workshop/skills/decorators/layers.py
index 5d1679c8..690a9368 100644
--- a/ovos_workshop/skills/decorators/layers.py
+++ b/ovos_workshop/skills/decorators/layers.py
@@ -1,130 +1,2 @@
-import inspect
-from functools import wraps
-
-from ovos_workshop.skills.layers import IntentLayers
-
-
-def dig_for_skill(max_records: int = 10):
-    from ovos_workshop.app import OVOSAbstractApplication
-    from ovos_workshop.skills import MycroftSkill
-    stack = inspect.stack()[1:]  # First frame will be this function call
-    stack = stack if len(stack) <= max_records else stack[:max_records]
-    for record in stack:
-        args = inspect.getargvalues(record.frame)
-        if args.locals.get("self"):
-            obj = args.locals["self"]
-            if isinstance(obj, MycroftSkill) or \
-                    isinstance(obj, OVOSAbstractApplication):
-                return obj
-        elif args.locals.get("args"):
-            for obj in args.locals["args"]:
-                if isinstance(obj, MycroftSkill) or \
-                        isinstance(obj, OVOSAbstractApplication):
-                    return obj
-    return None
-
-
-def enables_layer(layer_name):
-    def layer_handler(func):
-        @wraps(func)
-        def call_function(*args, **kwargs):
-            skill = dig_for_skill()
-            skill.intent_layers = skill.intent_layers or \
-                                  IntentLayers().bind(skill)
-            func(*args, **kwargs)
-            skill.intent_layers.activate_layer(layer_name)
-
-        return call_function
-
-    return layer_handler
-
-
-def disables_layer(layer_name):
-    def layer_handler(func):
-        @wraps(func)
-        def call_function(*args, **kwargs):
-            skill = dig_for_skill()
-            skill.intent_layers = skill.intent_layers or \
-                                  IntentLayers().bind(skill)
-            func(*args, **kwargs)
-            skill.intent_layers.deactivate_layer(layer_name)
-
-        return call_function
-
-    return layer_handler
-
-
-def replaces_layer(layer_name, intent_list):
-    def layer_handler(func):
-        @wraps(func)
-        def call_function(*args, **kwargs):
-            skill = dig_for_skill()
-            skill.intent_layers = skill.intent_layers or \
-                                  IntentLayers().bind(skill)
-            func(*args, **kwargs)
-            skill.intent_layers.replace_layer(layer_name, intent_list)
-
-        return call_function
-
-    return layer_handler
-
-
-def removes_layer(layer_name, intent_list):
-    def layer_handler(func):
-        @wraps(func)
-        def call_function(*args, **kwargs):
-            skill = dig_for_skill()
-            skill.intent_layers = skill.intent_layers or \
-                                  IntentLayers().bind(skill)
-            func(*args, **kwargs)
-            skill.intent_layers.replace_layer(layer_name, intent_list)
-
-        return call_function
-
-    return layer_handler
-
-
-def resets_layers():
-    def layer_handler(func):
-        @wraps(func)
-        def call_function(*args, **kwargs):
-            skill = dig_for_skill()
-            skill.intent_layers = skill.intent_layers or \
-                                  IntentLayers().bind(skill)
-            func(*args, **kwargs)
-            skill.intent_layers.disable()
-
-        return call_function
-
-    return layer_handler
-
-
-def layer_intent(intent_parser, layer_name):
-    """Decorator for adding a method as an intent handler belonging to an
-    intent layer."""
-
-    def real_decorator(func):
-        # Store the intent_parser inside the function
-        # This will be used later to call register_intent
-        if not hasattr(func, 'intents'):
-            func.intents = []
-        if not hasattr(func, 'intent_layers'):
-            func.intent_layers = {}
-
-        func.intents.append(intent_parser)
-        if layer_name not in func.intent_layers:
-            func.intent_layers[layer_name] = []
-
-        # get intent_name
-        if hasattr(intent_parser, "build"):
-            intent = intent_parser.build()
-            intent_name = intent.name or func.__name__
-        elif hasattr(intent_parser, "name"):
-            intent_name = intent_parser.name
-        else:
-            intent_name = intent_parser
-    
-        func.intent_layers[layer_name].append(intent_name)
-        return func
-
-    return real_decorator
+from ovos_workshop.decorators.layers import *
+# backwards compat import
diff --git a/ovos_workshop/skills/decorators/ocp.py b/ovos_workshop/skills/decorators/ocp.py
index 0c91a3eb..f20850fd 100644
--- a/ovos_workshop/skills/decorators/ocp.py
+++ b/ovos_workshop/skills/decorators/ocp.py
@@ -1,102 +1,2 @@
-from functools import wraps
-from ovos_workshop.skills.layers import IntentLayers
-from ovos_plugin_common_play.ocp import *
-from ovos_plugin_common_play.ocp.status import *
-
-
-def ocp_search():
-    """Decorator for adding a method as an common play search handler."""
-
-    def real_decorator(func):
-        # Store the flag inside the function
-        # This will be used later to identify the method
-        if not hasattr(func, 'is_ocp_search_handler'):
-            func.is_ocp_search_handler = True
-
-        return func
-
-    return real_decorator
-
-
-def ocp_play():
-    """Decorator for adding a method as an common play search handler."""
-
-    def real_decorator(func):
-        # Store the flag inside the function
-        # This will be used later to identify the method
-        if not hasattr(func, 'is_ocp_playback_handler'):
-            func.is_ocp_playback_handler = True
-
-        return func
-
-    return real_decorator
-
-
-def ocp_previous():
-    """Decorator for adding a method as an common play prev handler."""
-
-    def real_decorator(func):
-        # Store the flag inside the function
-        # This will be used later to identify the method
-        if not hasattr(func, 'is_ocp_prev_handler'):
-            func.is_ocp_prev_handler = True
-
-        return func
-
-    return real_decorator
-
-
-def ocp_next():
-    """Decorator for adding a method as an common play  next handler."""
-
-    def real_decorator(func):
-        # Store the flag inside the function
-        # This will be used later to identify the method
-        if not hasattr(func, 'is_ocp_next_handler'):
-            func.is_ocp_next_handler = True
-
-        return func
-
-    return real_decorator
-
-
-def ocp_pause():
-    """Decorator for adding a method as an common play pause handler."""
-
-    def real_decorator(func):
-        # Store the flag inside the function
-        # This will be used later to identify the method
-        if not hasattr(func, 'is_ocp_pause_handler'):
-            func.is_ocp_pause_handler = True
-
-        return func
-
-    return real_decorator
-
-
-def ocp_resume():
-    """Decorator for adding a method as an common play resume handler."""
-
-    def real_decorator(func):
-        # Store the flag inside the function
-        # This will be used later to identify the method
-        if not hasattr(func, 'is_ocp_resume_handler'):
-            func.is_ocp_resume_handler = True
-
-        return func
-
-    return real_decorator
-
-
-def ocp_featured_media():
-    """Decorator for adding a method as an common play search handler."""
-
-    def real_decorator(func):
-        # Store the flag inside the function
-        # This will be used later to identify the method
-        if not hasattr(func, 'is_ocp_featured_handler'):
-            func.is_ocp_featured_handler = True
-
-        return func
-
-    return real_decorator
+from ovos_workshop.decorators.ocp import *
+# backwards compat import
diff --git a/ovos_workshop/skills/ovos.py b/ovos_workshop/skills/ovos.py
index bb514aaf..d18153ae 100644
--- a/ovos_workshop/skills/ovos.py
+++ b/ovos_workshop/skills/ovos.py
@@ -14,7 +14,7 @@
 from ovos_utils.skills import get_non_properties
 from ovos_utils.intents import IntentBuilder, Intent, AdaptIntent
 from ovos_workshop.patches.base_skill import MycroftSkill, FallbackSkill
-from ovos_workshop.skills.decorators.killable import killable_event, \
+from ovos_workshop.decorators.killable import killable_event, \
     AbortEvent, AbortQuestion
 from ovos_workshop.skills.layers import IntentLayers