We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Skill Shutdown sometimes fails causing duplicate instances of Skill
## Devices:
Issue occurred on two separate Debian Linux installations
- one running Mycroft-core 19.02.14, 
- the other running dev branch the date of this issue.

## Steps to reproduce:
1. Load Mycroft and ensure working as expected
2. Make intentional code error in Alarm Skill to raise exception eg `self.log.info(not_a_real_var)`
3. Skill fails on reload with the following error:
```
 12:04:25.758 | INFO     | 22386 | mycroft.skills.skill_loader:reload:109 | ATTEMPTING TO RELOAD SKILL: mycroft-alarm.mycroftai
 12:04:25.760 | ERROR    | 22386 | mycroft.skills.skill_loader:_execute_instance_shutdown:145 | An error occurred while shutting down AlarmSkill
Traceback (most recent call last):
  File "/home/fs-neriahbjato/Documents/Full_Scale/Mycroft/mycroft-core/mycroft/skills/skill_loader.py", line 142, in _execute_instance_shutdown
    self.instance.default_shutdown()
  File "/home/fs-neriahbjato/Documents/Full_Scale/Mycroft/mycroft-core/mycroft/skills/mycroft_skill/mycroft_skill.py", line 1162, in default_shutdown
    self.event_scheduler.shutdown()
  File "/home/fs-neriahbjato/Documents/Full_Scale/Mycroft/mycroft-core/mycroft/skills/event_scheduler.py", line 433, in shutdown
    self.events.clear()
  File "/home/fs-neriahbjato/Documents/Full_Scale/Mycroft/mycroft-core/mycroft/skills/mycroft_skill/event_container.py", line 183, in clear
    self.bus.remove(e, f)
  File "/home/fs-neriahbjato/Documents/Full_Scale/Mycroft/mycroft-core/mycroft/messagebus/client/client.py", line 172, in remove
    self.emitter.remove_listener(event_name, func)
  File "/home/fs-neriahbjato/Documents/Full_Scale/Mycroft/mycroft-core/mycroft/messagebus/client/threaded_event_emitter.py", line 57, in remove_listener
    return super().remove_listener(event_name, func)
  File "/home/fs-neriahbjato/Documents/Full_Scale/Mycroft/mycroft-core/.venv/lib/python3.6/site-packages/pyee/__init__.py", line 205, in remove_listener
    self._events[event].pop(f)
KeyError: <function create_basic_wrapper.<locals>.wrapper at 0x7f2a504781e0>
```
4. Remove bad code and save to reload Skill
```
 12:04:25.803 | INFO     | 22386 | mycroft.skills.skill_loader:_communicate_load_status:273 | Skill mycroft-alarm.mycroftai loaded successfully
```
5. Trigger the Skill with an utterance eg "what alarms are set"
6. Mycroft responds twice
  - once from the failed instance of the Skill: "An error occurred while processing a request in Alarm Skill"
  - once from the new working instance of the Skill: "No alarms have been set"

The failed instance of the Skill will remain until Mycroft services are restarted.
After restarting, the same steps cause the same error.

## Investigation:
This was only occurring for the Alarm Skill, did not get the same behavior in the Date Time Skill.
To see what might be causing it, I added some logging to the offending function in [`mycroft/messagebus/client/threaded_event_emitter.py`](https://github.com/MycroftAI/mycroft-core/blob/dev/mycroft/messagebus/client/threaded_event_emitter.py):
```
def remove_listener(self, event_name, func):
        """ Wrap the remove to translate from function to wrapped
            function.
        """
        for w in self.wrappers[event_name]:
            if w[0] == func:
                self.wrappers[event_name].remove(w)
                return super().remove_listener(event_name, w[1])
        # if no wrapper exists try removing the function
        LOG.info("REMOVING LISTENER")
        LOG.info("event_name: " + str(event_name))
        LOG.info(event_name)
        LOG.info("func: " + str(func))
        LOG.info(func)
        return super().remove_listener(event_name, func)
```
Then reloaded Mycroft and can no longer trigger the issue.

## Hypothesis
- Presumably the `func` was not being found in `self.wrappers` allowing it to proceed to try removing the function itself on [line 57](https://github.com/MycroftAI/mycroft-core/blob/dev/mycroft/messagebus/client/threaded_event_emitter.py#L57) which then failed.
- Possibly the function was modified or removed from `self.wrappers` causing it to not match?
- Is `self.wrappers` cached between service restarts, and would editing this file have recreated it?


As I'm no longer able to reproduce the error it's difficult to continue debugging. So documenting the situation here in case anyone else runs into it and we can pick it back up.

Unless anyone else has an idea of what might be happening?

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `mycroft/skills/mycroft_skill/event_container.py`
Content:
```
1 from inspect import signature
2 
3 from mycroft.messagebus.message import Message
4 from mycroft.metrics import Stopwatch, report_timing
5 from mycroft.util.log import LOG
6 
7 from ..skill_data import to_alnum
8 
9 
10 def unmunge_message(message, skill_id):
11     """Restore message keywords by removing the Letterified skill ID.
12     Arguments:
13         message (Message): Intent result message
14         skill_id (str): skill identifier
15     Returns:
16         Message without clear keywords
17     """
18     if isinstance(message, Message) and isinstance(message.data, dict):
19         skill_id = to_alnum(skill_id)
20         for key in list(message.data.keys()):
21             if key.startswith(skill_id):
22                 # replace the munged key with the real one
23                 new_key = key[len(skill_id):]
24                 message.data[new_key] = message.data.pop(key)
25 
26     return message
27 
28 
29 def get_handler_name(handler):
30     """Name (including class if available) of handler function.
31 
32     Arguments:
33         handler (function): Function to be named
34 
35     Returns:
36         string: handler name as string
37     """
38     if '__self__' in dir(handler) and 'name' in dir(handler.__self__):
39         return handler.__self__.name + '.' + handler.__name__
40     else:
41         return handler.__name__
42 
43 
44 def create_wrapper(handler, skill_id, on_start, on_end, on_error):
45     """Create the default skill handler wrapper.
46 
47     This wrapper handles things like metrics, reporting handler start/stop
48     and errors.
49         handler (callable): method/function to call
50         skill_id: skill_id for associated skill
51         on_start (function): function to call before executing the handler
52         on_end (function): function to call after executing the handler
53         on_error (function): function to call for error reporting
54     """
55     def wrapper(message):
56         stopwatch = Stopwatch()
57         try:
58             message = unmunge_message(message, skill_id)
59             if on_start:
60                 on_start(message)
61 
62             with stopwatch:
63                 if len(signature(handler).parameters) == 0:
64                     handler()
65                 else:
66                     handler(message)
67 
68         except Exception as e:
69             if on_error:
70                 on_error(e)
71         finally:
72             if on_end:
73                 on_end(message)
74 
75             # Send timing metrics
76             context = message.context
77             if context and 'ident' in context:
78                 report_timing(context['ident'], 'skill_handler', stopwatch,
79                               {'handler': handler.__name__,
80                                'skill_id': skill_id})
81     return wrapper
82 
83 
84 def create_basic_wrapper(handler, on_error=None):
85     """Create the default skill handler wrapper.
86 
87     This wrapper handles things like metrics, reporting handler start/stop
88     and errors.
89 
90     Arguments:
91         handler (callable): method/function to call
92         on_error (function): function to call to report error.
93 
94     Returns:
95         Wrapped callable
96     """
97     def wrapper(message):
98         try:
99             if len(signature(handler).parameters) == 0:
100                 handler()
101             else:
102                 handler(message)
103         except Exception as e:
104             if on_error:
105                 on_error(e)
106 
107     return wrapper
108 
109 
110 class EventContainer:
111     """Container tracking messagbus handlers.
112 
113     This container tracks events added by a skill, allowing unregistering
114     all events on shutdown.
115     """
116     def __init__(self, bus=None):
117         self.bus = bus
118         self.events = []
119 
120     def set_bus(self, bus):
121         self.bus = bus
122 
123     def add(self, name, handler, once=False):
124         """Create event handler for executing intent or other event.
125 
126         Arguments:
127             name (string): IntentParser name
128             handler (func): Method to call
129             once (bool, optional): Event handler will be removed after it has
130                                    been run once.
131         """
132         def once_wrapper(message):
133             # Remove registered one-time handler before invoking,
134             # allowing them to re-schedule themselves.
135             handler(message)
136             self.remove(name)
137 
138         if handler:
139             if once:
140                 self.bus.once(name, once_wrapper)
141             else:
142                 self.bus.on(name, handler)
143             self.events.append((name, handler))
144 
145     def remove(self, name):
146         """Removes an event from bus emitter and events list.
147 
148         Args:
149             name (string): Name of Intent or Scheduler Event
150         Returns:
151             bool: True if found and removed, False if not found
152         """
153         print("Removing event {}".format(name))
154         removed = False
155         for _name, _handler in list(self.events):
156             if name == _name:
157                 try:
158                     self.events.remove((_name, _handler))
159                 except ValueError:
160                     LOG.error('Failed to remove event {}'.format(name))
161                     pass
162                 removed = True
163 
164         # Because of function wrappers, the emitter doesn't always directly
165         # hold the _handler function, it sometimes holds something like
166         # 'wrapper(_handler)'.  So a call like:
167         #     self.bus.remove(_name, _handler)
168         # will not find it, leaving an event handler with that name left behind
169         # waiting to fire if it is ever re-installed and triggered.
170         # Remove all handlers with the given name, regardless of handler.
171         if removed:
172             self.bus.remove_all_listeners(name)
173         return removed
174 
175     def __iter__(self):
176         return iter(self.events)
177 
178     def clear(self):
179         """Unregister all registered handlers and clear the list of registered
180         events.
181         """
182         for e, f in self.events:
183             self.bus.remove(e, f)
184         self.events = []  # Remove reference to wrappers
185
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/mycroft/skills/mycroft_skill/event_container.py b/mycroft/skills/mycroft_skill/event_container.py
--- a/mycroft/skills/mycroft_skill/event_container.py
+++ b/mycroft/skills/mycroft_skill/event_container.py
@@ -138,9 +138,12 @@
         if handler:
             if once:
                 self.bus.once(name, once_wrapper)
+                self.events.append((name, once_wrapper))
             else:
                 self.bus.on(name, handler)
-            self.events.append((name, handler))
+                self.events.append((name, handler))
+
+            LOG.debug('Added event: {}'.format(name))
 
     def remove(self, name):
         """Removes an event from bus emitter and events list.

{"golden_diff": "diff --git a/mycroft/skills/mycroft_skill/event_container.py b/mycroft/skills/mycroft_skill/event_container.py\n--- a/mycroft/skills/mycroft_skill/event_container.py\n+++ b/mycroft/skills/mycroft_skill/event_container.py\n@@ -138,9 +138,12 @@\n         if handler:\n             if once:\n                 self.bus.once(name, once_wrapper)\n+                self.events.append((name, once_wrapper))\n             else:\n                 self.bus.on(name, handler)\n-            self.events.append((name, handler))\n+                self.events.append((name, handler))\n+\n+            LOG.debug('Added event: {}'.format(name))\n \n     def remove(self, name):\n         \"\"\"Removes an event from bus emitter and events list.\n", "issue": "Skill Shutdown sometimes fails causing duplicate instances of Skill\n## Devices:\r\nIssue occurred on two separate Debian Linux installations\r\n- one running Mycroft-core 19.02.14, \r\n- the other running dev branch the date of this issue.\r\n\r\n## Steps to reproduce:\r\n1. Load Mycroft and ensure working as expected\r\n2. Make intentional code error in Alarm Skill to raise exception eg `self.log.info(not_a_real_var)`\r\n3. Skill fails on reload with the following error:\r\n```\r\n 12:04:25.758 | INFO     | 22386 | mycroft.skills.skill_loader:reload:109 | ATTEMPTING TO RELOAD SKILL: mycroft-alarm.mycroftai\r\n 12:04:25.760 | ERROR    | 22386 | mycroft.skills.skill_loader:_execute_instance_shutdown:145 | An error occurred while shutting down AlarmSkill\r\nTraceback (most recent call last):\r\n  File \"/home/fs-neriahbjato/Documents/Full_Scale/Mycroft/mycroft-core/mycroft/skills/skill_loader.py\", line 142, in _execute_instance_shutdown\r\n    self.instance.default_shutdown()\r\n  File \"/home/fs-neriahbjato/Documents/Full_Scale/Mycroft/mycroft-core/mycroft/skills/mycroft_skill/mycroft_skill.py\", line 1162, in default_shutdown\r\n    self.event_scheduler.shutdown()\r\n  File \"/home/fs-neriahbjato/Documents/Full_Scale/Mycroft/mycroft-core/mycroft/skills/event_scheduler.py\", line 433, in shutdown\r\n    self.events.clear()\r\n  File \"/home/fs-neriahbjato/Documents/Full_Scale/Mycroft/mycroft-core/mycroft/skills/mycroft_skill/event_container.py\", line 183, in clear\r\n    self.bus.remove(e, f)\r\n  File \"/home/fs-neriahbjato/Documents/Full_Scale/Mycroft/mycroft-core/mycroft/messagebus/client/client.py\", line 172, in remove\r\n    self.emitter.remove_listener(event_name, func)\r\n  File \"/home/fs-neriahbjato/Documents/Full_Scale/Mycroft/mycroft-core/mycroft/messagebus/client/threaded_event_emitter.py\", line 57, in remove_listener\r\n    return super().remove_listener(event_name, func)\r\n  File \"/home/fs-neriahbjato/Documents/Full_Scale/Mycroft/mycroft-core/.venv/lib/python3.6/site-packages/pyee/__init__.py\", line 205, in remove_listener\r\n    self._events[event].pop(f)\r\nKeyError: <function create_basic_wrapper.<locals>.wrapper at 0x7f2a504781e0>\r\n```\r\n4. Remove bad code and save to reload Skill\r\n```\r\n 12:04:25.803 | INFO     | 22386 | mycroft.skills.skill_loader:_communicate_load_status:273 | Skill mycroft-alarm.mycroftai loaded successfully\r\n```\r\n5. Trigger the Skill with an utterance eg \"what alarms are set\"\r\n6. Mycroft responds twice\r\n  - once from the failed instance of the Skill: \"An error occurred while processing a request in Alarm Skill\"\r\n  - once from the new working instance of the Skill: \"No alarms have been set\"\r\n\r\nThe failed instance of the Skill will remain until Mycroft services are restarted.\r\nAfter restarting, the same steps cause the same error.\r\n\r\n## Investigation:\r\nThis was only occurring for the Alarm Skill, did not get the same behavior in the Date Time Skill.\r\nTo see what might be causing it, I added some logging to the offending function in [`mycroft/messagebus/client/threaded_event_emitter.py`](https://github.com/MycroftAI/mycroft-core/blob/dev/mycroft/messagebus/client/threaded_event_emitter.py):\r\n```\r\ndef remove_listener(self, event_name, func):\r\n        \"\"\" Wrap the remove to translate from function to wrapped\r\n            function.\r\n        \"\"\"\r\n        for w in self.wrappers[event_name]:\r\n            if w[0] == func:\r\n                self.wrappers[event_name].remove(w)\r\n                return super().remove_listener(event_name, w[1])\r\n        # if no wrapper exists try removing the function\r\n        LOG.info(\"REMOVING LISTENER\")\r\n        LOG.info(\"event_name: \" + str(event_name))\r\n        LOG.info(event_name)\r\n        LOG.info(\"func: \" + str(func))\r\n        LOG.info(func)\r\n        return super().remove_listener(event_name, func)\r\n```\r\nThen reloaded Mycroft and can no longer trigger the issue.\r\n\r\n## Hypothesis\r\n- Presumably the `func` was not being found in `self.wrappers` allowing it to proceed to try removing the function itself on [line 57](https://github.com/MycroftAI/mycroft-core/blob/dev/mycroft/messagebus/client/threaded_event_emitter.py#L57) which then failed.\r\n- Possibly the function was modified or removed from `self.wrappers` causing it to not match?\r\n- Is `self.wrappers` cached between service restarts, and would editing this file have recreated it?\r\n\r\n\r\nAs I'm no longer able to reproduce the error it's difficult to continue debugging. So documenting the situation here in case anyone else runs into it and we can pick it back up.\r\n\r\nUnless anyone else has an idea of what might be happening?\n", "before_files": [{"content": "from inspect import signature\n\nfrom mycroft.messagebus.message import Message\nfrom mycroft.metrics import Stopwatch, report_timing\nfrom mycroft.util.log import LOG\n\nfrom ..skill_data import to_alnum\n\n\ndef unmunge_message(message, skill_id):\n    \"\"\"Restore message keywords by removing the Letterified skill ID.\n    Arguments:\n        message (Message): Intent result message\n        skill_id (str): skill identifier\n    Returns:\n        Message without clear keywords\n    \"\"\"\n    if isinstance(message, Message) and isinstance(message.data, dict):\n        skill_id = to_alnum(skill_id)\n        for key in list(message.data.keys()):\n            if key.startswith(skill_id):\n                # replace the munged key with the real one\n                new_key = key[len(skill_id):]\n                message.data[new_key] = message.data.pop(key)\n\n    return message\n\n\ndef get_handler_name(handler):\n    \"\"\"Name (including class if available) of handler function.\n\n    Arguments:\n        handler (function): Function to be named\n\n    Returns:\n        string: handler name as string\n    \"\"\"\n    if '__self__' in dir(handler) and 'name' in dir(handler.__self__):\n        return handler.__self__.name + '.' + handler.__name__\n    else:\n        return handler.__name__\n\n\ndef create_wrapper(handler, skill_id, on_start, on_end, on_error):\n    \"\"\"Create the default skill handler wrapper.\n\n    This wrapper handles things like metrics, reporting handler start/stop\n    and errors.\n        handler (callable): method/function to call\n        skill_id: skill_id for associated skill\n        on_start (function): function to call before executing the handler\n        on_end (function): function to call after executing the handler\n        on_error (function): function to call for error reporting\n    \"\"\"\n    def wrapper(message):\n        stopwatch = Stopwatch()\n        try:\n            message = unmunge_message(message, skill_id)\n            if on_start:\n                on_start(message)\n\n            with stopwatch:\n                if len(signature(handler).parameters) == 0:\n                    handler()\n                else:\n                    handler(message)\n\n        except Exception as e:\n            if on_error:\n                on_error(e)\n        finally:\n            if on_end:\n                on_end(message)\n\n            # Send timing metrics\n            context = message.context\n            if context and 'ident' in context:\n                report_timing(context['ident'], 'skill_handler', stopwatch,\n                              {'handler': handler.__name__,\n                               'skill_id': skill_id})\n    return wrapper\n\n\ndef create_basic_wrapper(handler, on_error=None):\n    \"\"\"Create the default skill handler wrapper.\n\n    This wrapper handles things like metrics, reporting handler start/stop\n    and errors.\n\n    Arguments:\n        handler (callable): method/function to call\n        on_error (function): function to call to report error.\n\n    Returns:\n        Wrapped callable\n    \"\"\"\n    def wrapper(message):\n        try:\n            if len(signature(handler).parameters) == 0:\n                handler()\n            else:\n                handler(message)\n        except Exception as e:\n            if on_error:\n                on_error(e)\n\n    return wrapper\n\n\nclass EventContainer:\n    \"\"\"Container tracking messagbus handlers.\n\n    This container tracks events added by a skill, allowing unregistering\n    all events on shutdown.\n    \"\"\"\n    def __init__(self, bus=None):\n        self.bus = bus\n        self.events = []\n\n    def set_bus(self, bus):\n        self.bus = bus\n\n    def add(self, name, handler, once=False):\n        \"\"\"Create event handler for executing intent or other event.\n\n        Arguments:\n            name (string): IntentParser name\n            handler (func): Method to call\n            once (bool, optional): Event handler will be removed after it has\n                                   been run once.\n        \"\"\"\n        def once_wrapper(message):\n            # Remove registered one-time handler before invoking,\n            # allowing them to re-schedule themselves.\n            handler(message)\n            self.remove(name)\n\n        if handler:\n            if once:\n                self.bus.once(name, once_wrapper)\n            else:\n                self.bus.on(name, handler)\n            self.events.append((name, handler))\n\n    def remove(self, name):\n        \"\"\"Removes an event from bus emitter and events list.\n\n        Args:\n            name (string): Name of Intent or Scheduler Event\n        Returns:\n            bool: True if found and removed, False if not found\n        \"\"\"\n        print(\"Removing event {}\".format(name))\n        removed = False\n        for _name, _handler in list(self.events):\n            if name == _name:\n                try:\n                    self.events.remove((_name, _handler))\n                except ValueError:\n                    LOG.error('Failed to remove event {}'.format(name))\n                    pass\n                removed = True\n\n        # Because of function wrappers, the emitter doesn't always directly\n        # hold the _handler function, it sometimes holds something like\n        # 'wrapper(_handler)'.  So a call like:\n        #     self.bus.remove(_name, _handler)\n        # will not find it, leaving an event handler with that name left behind\n        # waiting to fire if it is ever re-installed and triggered.\n        # Remove all handlers with the given name, regardless of handler.\n        if removed:\n            self.bus.remove_all_listeners(name)\n        return removed\n\n    def __iter__(self):\n        return iter(self.events)\n\n    def clear(self):\n        \"\"\"Unregister all registered handlers and clear the list of registered\n        events.\n        \"\"\"\n        for e, f in self.events:\n            self.bus.remove(e, f)\n        self.events = []  # Remove reference to wrappers\n", "path": "mycroft/skills/mycroft_skill/event_container.py"}], "after_files": [{"content": "from inspect import signature\n\nfrom mycroft.messagebus.message import Message\nfrom mycroft.metrics import Stopwatch, report_timing\nfrom mycroft.util.log import LOG\n\nfrom ..skill_data import to_alnum\n\n\ndef unmunge_message(message, skill_id):\n    \"\"\"Restore message keywords by removing the Letterified skill ID.\n    Arguments:\n        message (Message): Intent result message\n        skill_id (str): skill identifier\n    Returns:\n        Message without clear keywords\n    \"\"\"\n    if isinstance(message, Message) and isinstance(message.data, dict):\n        skill_id = to_alnum(skill_id)\n        for key in list(message.data.keys()):\n            if key.startswith(skill_id):\n                # replace the munged key with the real one\n                new_key = key[len(skill_id):]\n                message.data[new_key] = message.data.pop(key)\n\n    return message\n\n\ndef get_handler_name(handler):\n    \"\"\"Name (including class if available) of handler function.\n\n    Arguments:\n        handler (function): Function to be named\n\n    Returns:\n        string: handler name as string\n    \"\"\"\n    if '__self__' in dir(handler) and 'name' in dir(handler.__self__):\n        return handler.__self__.name + '.' + handler.__name__\n    else:\n        return handler.__name__\n\n\ndef create_wrapper(handler, skill_id, on_start, on_end, on_error):\n    \"\"\"Create the default skill handler wrapper.\n\n    This wrapper handles things like metrics, reporting handler start/stop\n    and errors.\n        handler (callable): method/function to call\n        skill_id: skill_id for associated skill\n        on_start (function): function to call before executing the handler\n        on_end (function): function to call after executing the handler\n        on_error (function): function to call for error reporting\n    \"\"\"\n    def wrapper(message):\n        stopwatch = Stopwatch()\n        try:\n            message = unmunge_message(message, skill_id)\n            if on_start:\n                on_start(message)\n\n            with stopwatch:\n                if len(signature(handler).parameters) == 0:\n                    handler()\n                else:\n                    handler(message)\n\n        except Exception as e:\n            if on_error:\n                on_error(e)\n        finally:\n            if on_end:\n                on_end(message)\n\n            # Send timing metrics\n            context = message.context\n            if context and 'ident' in context:\n                report_timing(context['ident'], 'skill_handler', stopwatch,\n                              {'handler': handler.__name__,\n                               'skill_id': skill_id})\n    return wrapper\n\n\ndef create_basic_wrapper(handler, on_error=None):\n    \"\"\"Create the default skill handler wrapper.\n\n    This wrapper handles things like metrics, reporting handler start/stop\n    and errors.\n\n    Arguments:\n        handler (callable): method/function to call\n        on_error (function): function to call to report error.\n\n    Returns:\n        Wrapped callable\n    \"\"\"\n    def wrapper(message):\n        try:\n            if len(signature(handler).parameters) == 0:\n                handler()\n            else:\n                handler(message)\n        except Exception as e:\n            if on_error:\n                on_error(e)\n\n    return wrapper\n\n\nclass EventContainer:\n    \"\"\"Container tracking messagbus handlers.\n\n    This container tracks events added by a skill, allowing unregistering\n    all events on shutdown.\n    \"\"\"\n    def __init__(self, bus=None):\n        self.bus = bus\n        self.events = []\n\n    def set_bus(self, bus):\n        self.bus = bus\n\n    def add(self, name, handler, once=False):\n        \"\"\"Create event handler for executing intent or other event.\n\n        Arguments:\n            name (string): IntentParser name\n            handler (func): Method to call\n            once (bool, optional): Event handler will be removed after it has\n                                   been run once.\n        \"\"\"\n        def once_wrapper(message):\n            # Remove registered one-time handler before invoking,\n            # allowing them to re-schedule themselves.\n            handler(message)\n            self.remove(name)\n\n        if handler:\n            if once:\n                self.bus.once(name, once_wrapper)\n                self.events.append((name, once_wrapper))\n            else:\n                self.bus.on(name, handler)\n                self.events.append((name, handler))\n\n            LOG.debug('Added event: {}'.format(name))\n\n    def remove(self, name):\n        \"\"\"Removes an event from bus emitter and events list.\n\n        Args:\n            name (string): Name of Intent or Scheduler Event\n        Returns:\n            bool: True if found and removed, False if not found\n        \"\"\"\n        print(\"Removing event {}\".format(name))\n        removed = False\n        for _name, _handler in list(self.events):\n            if name == _name:\n                try:\n                    self.events.remove((_name, _handler))\n                except ValueError:\n                    LOG.error('Failed to remove event {}'.format(name))\n                    pass\n                removed = True\n\n        # Because of function wrappers, the emitter doesn't always directly\n        # hold the _handler function, it sometimes holds something like\n        # 'wrapper(_handler)'.  So a call like:\n        #     self.bus.remove(_name, _handler)\n        # will not find it, leaving an event handler with that name left behind\n        # waiting to fire if it is ever re-installed and triggered.\n        # Remove all handlers with the given name, regardless of handler.\n        if removed:\n            self.bus.remove_all_listeners(name)\n        return removed\n\n    def __iter__(self):\n        return iter(self.events)\n\n    def clear(self):\n        \"\"\"Unregister all registered handlers and clear the list of registered\n        events.\n        \"\"\"\n        for e, f in self.events:\n            self.bus.remove(e, f)\n        self.events = []  # Remove reference to wrappers\n", "path": "mycroft/skills/mycroft_skill/event_container.py"}]}