prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  self.remove_fallback(handler) it does not work
  i need the remove.fallback function after recording in my wakeword skill. I acted according to instructions https://mycroft-ai.gitbook.io/docs/skill-development/skill-types/fallback-skill. however, I always get the message. "mycroft.skills.fallback_skill:remove_fallback:139 | Could not remove fallback!". the fallback function is retained and is not deactivated. During the skill shutdown, the function is executed, the error message remains and fallback is deactivated.
  
  
  --- 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/fallback_skill.py`
  Content:
  ```
  1 # Copyright 2019 Mycroft AI Inc.
  2 #
  3 # Licensed under the Apache License, Version 2.0 (the "License");
  4 # you may not use this file except in compliance with the License.
  5 # You may obtain a copy of the License at
  6 #
  7 #    http://www.apache.org/licenses/LICENSE-2.0
  8 #
  9 # Unless required by applicable law or agreed to in writing, software
  10 # distributed under the License is distributed on an "AS IS" BASIS,
  11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12 # See the License for the specific language governing permissions and
  13 # limitations under the License.
  14 #
  15 """The fallback skill implements a special type of skill handling
  16 utterances not handled by the intent system.
  17 """
  18 import operator
  19 from mycroft.metrics import report_timing, Stopwatch
  20 from mycroft.util.log import LOG
  21 
  22 
  23 from .mycroft_skill import MycroftSkill, get_handler_name
  24 
  25 
  26 class FallbackSkill(MycroftSkill):
  27     """Fallbacks come into play when no skill matches an Adapt or closely with
  28     a Padatious intent.  All Fallback skills work together to give them a
  29     view of the user's utterance.  Fallback handlers are called in an order
  30     determined the priority provided when the the handler is registered.
  31 
  32     ========   ========   ================================================
  33     Priority   Who?       Purpose
  34     ========   ========   ================================================
  35        1-4     RESERVED   Unused for now, slot for pre-Padatious if needed
  36          5     MYCROFT    Padatious near match (conf > 0.8)
  37       6-88     USER       General
  38         89     MYCROFT    Padatious loose match (conf > 0.5)
  39      90-99     USER       Uncaught intents
  40        100+    MYCROFT    Fallback Unknown or other future use
  41     ========   ========   ================================================
  42 
  43     Handlers with the numerically lowest priority are invoked first.
  44     Multiple fallbacks can exist at the same priority, but no order is
  45     guaranteed.
  46 
  47     A Fallback can either observe or consume an utterance. A consumed
  48     utterance will not be see by any other Fallback handlers.
  49     """
  50     fallback_handlers = {}
  51 
  52     def __init__(self, name=None, bus=None, use_settings=True):
  53         super().__init__(name, bus, use_settings)
  54 
  55         #  list of fallback handlers registered by this instance
  56         self.instance_fallback_handlers = []
  57 
  58     @classmethod
  59     def make_intent_failure_handler(cls, bus):
  60         """Goes through all fallback handlers until one returns True"""
  61 
  62         def handler(message):
  63             # indicate fallback handling start
  64             bus.emit(message.forward("mycroft.skill.handler.start",
  65                                      data={'handler': "fallback"}))
  66 
  67             stopwatch = Stopwatch()
  68             handler_name = None
  69             with stopwatch:
  70                 for _, handler in sorted(cls.fallback_handlers.items(),
  71                                          key=operator.itemgetter(0)):
  72                     try:
  73                         if handler(message):
  74                             #  indicate completion
  75                             handler_name = get_handler_name(handler)
  76                             bus.emit(message.forward(
  77                                      'mycroft.skill.handler.complete',
  78                                      data={'handler': "fallback",
  79                                            "fallback_handler": handler_name}))
  80                             break
  81                     except Exception:
  82                         LOG.exception('Exception in fallback.')
  83                 else:  # No fallback could handle the utterance
  84                     bus.emit(message.forward('complete_intent_failure'))
  85                     warning = "No fallback could handle intent."
  86                     LOG.warning(warning)
  87                     #  indicate completion with exception
  88                     bus.emit(message.forward('mycroft.skill.handler.complete',
  89                                              data={'handler': "fallback",
  90                                                    'exception': warning}))
  91 
  92             # Send timing metric
  93             if message.context.get('ident'):
  94                 ident = message.context['ident']
  95                 report_timing(ident, 'fallback_handler', stopwatch,
  96                               {'handler': handler_name})
  97 
  98         return handler
  99 
  100     @classmethod
  101     def _register_fallback(cls, handler, priority):
  102         """Register a function to be called as a general info fallback
  103         Fallback should receive message and return
  104         a boolean (True if succeeded or False if failed)
  105 
  106         Lower priority gets run first
  107         0 for high priority 100 for low priority
  108         """
  109         while priority in cls.fallback_handlers:
  110             priority += 1
  111 
  112         cls.fallback_handlers[priority] = handler
  113 
  114     def register_fallback(self, handler, priority):
  115         """Register a fallback with the list of fallback handlers and with the
  116         list of handlers registered by this instance
  117         """
  118 
  119         def wrapper(*args, **kwargs):
  120             if handler(*args, **kwargs):
  121                 self.make_active()
  122                 return True
  123             return False
  124 
  125         self.instance_fallback_handlers.append(wrapper)
  126         self._register_fallback(wrapper, priority)
  127 
  128     @classmethod
  129     def remove_fallback(cls, handler_to_del):
  130         """Remove a fallback handler.
  131 
  132         Arguments:
  133             handler_to_del: reference to handler
  134         """
  135         for priority, handler in cls.fallback_handlers.items():
  136             if handler == handler_to_del:
  137                 del cls.fallback_handlers[priority]
  138                 return
  139         LOG.warning('Could not remove fallback!')
  140 
  141     def remove_instance_handlers(self):
  142         """Remove all fallback handlers registered by the fallback skill."""
  143         while len(self.instance_fallback_handlers):
  144             handler = self.instance_fallback_handlers.pop()
  145             self.remove_fallback(handler)
  146 
  147     def default_shutdown(self):
  148         """Remove all registered handlers and perform skill shutdown."""
  149         self.remove_instance_handlers()
  150         super(FallbackSkill, self).default_shutdown()
  151
  ```
  --- 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()
  
  ```
  
golden_diff: diff --git a/mycroft/skills/fallback_skill.py b/mycroft/skills/fallback_skill.py
  --- a/mycroft/skills/fallback_skill.py
  +++ b/mycroft/skills/fallback_skill.py
  @@ -48,6 +48,7 @@
       utterance will not be see by any other Fallback handlers.
       """
       fallback_handlers = {}
  +    wrapper_map = []  # Map containing (handler, wrapper) tuples
   
       def __init__(self, name=None, bus=None, use_settings=True):
           super().__init__(name, bus, use_settings)
  @@ -98,18 +99,25 @@
           return handler
   
       @classmethod
  -    def _register_fallback(cls, handler, priority):
  +    def _register_fallback(cls, handler, wrapper, priority):
           """Register a function to be called as a general info fallback
           Fallback should receive message and return
           a boolean (True if succeeded or False if failed)
   
           Lower priority gets run first
           0 for high priority 100 for low priority
  +
  +        Arguments:
  +            handler (callable): original handler, used as a reference when
  +                                removing
  +            wrapper (callable): wrapped version of handler
  +            priority (int): fallback priority
           """
           while priority in cls.fallback_handlers:
               priority += 1
   
  -        cls.fallback_handlers[priority] = handler
  +        cls.fallback_handlers[priority] = wrapper
  +        cls.wrapper_map.append((handler, wrapper))
   
       def register_fallback(self, handler, priority):
           """Register a fallback with the list of fallback handlers and with the
  @@ -122,8 +130,28 @@
                   return True
               return False
   
  -        self.instance_fallback_handlers.append(wrapper)
  -        self._register_fallback(wrapper, priority)
  +        self.instance_fallback_handlers.append(handler)
  +        self._register_fallback(handler, wrapper, priority)
  +
  +    @classmethod
  +    def _remove_registered_handler(cls, wrapper_to_del):
  +        """Remove a registered wrapper.
  +
  +        Arguments:
  +            wrapper_to_del (callable): wrapped handler to be removed
  +
  +        Returns:
  +            (bool) True if one or more handlers were removed, otherwise False.
  +        """
  +        found_handler = False
  +        for priority, handler in list(cls.fallback_handlers.items()):
  +            if handler == wrapper_to_del:
  +                found_handler = True
  +                del cls.fallback_handlers[priority]
  +
  +        if not found_handler:
  +            LOG.warning('No fallback matching {}'.format(wrapper_to_del))
  +        return found_handler
   
       @classmethod
       def remove_fallback(cls, handler_to_del):
  @@ -131,15 +159,27 @@
   
           Arguments:
               handler_to_del: reference to handler
  +        Returns:
  +            (bool) True if at least one handler was removed, otherwise False
           """
  -        for priority, handler in cls.fallback_handlers.items():
  -            if handler == handler_to_del:
  -                del cls.fallback_handlers[priority]
  -                return
  -        LOG.warning('Could not remove fallback!')
  +        # Find wrapper from handler or wrapper
  +        wrapper_to_del = None
  +        for h, w in cls.wrapper_map:
  +            if handler_to_del in (h, w):
  +                wrapper_to_del = w
  +                break
  +
  +        if wrapper_to_del:
  +            cls.wrapper_map.remove((h, w))
  +            remove_ok = cls._remove_registered_handler(wrapper_to_del)
  +        else:
  +            LOG.warning('Could not find matching fallback handler')
  +            remove_ok = False
  +        return remove_ok
   
       def remove_instance_handlers(self):
           """Remove all fallback handlers registered by the fallback skill."""
  +        self.log.info('Removing all handlers...')
           while len(self.instance_fallback_handlers):
               handler = self.instance_fallback_handlers.pop()
               self.remove_fallback(handler)
  
verification_info: {"golden_diff": "diff --git a/mycroft/skills/fallback_skill.py b/mycroft/skills/fallback_skill.py\n--- a/mycroft/skills/fallback_skill.py\n+++ b/mycroft/skills/fallback_skill.py\n@@ -48,6 +48,7 @@\n     utterance will not be see by any other Fallback handlers.\n     \"\"\"\n     fallback_handlers = {}\n+    wrapper_map = []  # Map containing (handler, wrapper) tuples\n \n     def __init__(self, name=None, bus=None, use_settings=True):\n         super().__init__(name, bus, use_settings)\n@@ -98,18 +99,25 @@\n         return handler\n \n     @classmethod\n-    def _register_fallback(cls, handler, priority):\n+    def _register_fallback(cls, handler, wrapper, priority):\n         \"\"\"Register a function to be called as a general info fallback\n         Fallback should receive message and return\n         a boolean (True if succeeded or False if failed)\n \n         Lower priority gets run first\n         0 for high priority 100 for low priority\n+\n+        Arguments:\n+            handler (callable): original handler, used as a reference when\n+                                removing\n+            wrapper (callable): wrapped version of handler\n+            priority (int): fallback priority\n         \"\"\"\n         while priority in cls.fallback_handlers:\n             priority += 1\n \n-        cls.fallback_handlers[priority] = handler\n+        cls.fallback_handlers[priority] = wrapper\n+        cls.wrapper_map.append((handler, wrapper))\n \n     def register_fallback(self, handler, priority):\n         \"\"\"Register a fallback with the list of fallback handlers and with the\n@@ -122,8 +130,28 @@\n                 return True\n             return False\n \n-        self.instance_fallback_handlers.append(wrapper)\n-        self._register_fallback(wrapper, priority)\n+        self.instance_fallback_handlers.append(handler)\n+        self._register_fallback(handler, wrapper, priority)\n+\n+    @classmethod\n+    def _remove_registered_handler(cls, wrapper_to_del):\n+        \"\"\"Remove a registered wrapper.\n+\n+        Arguments:\n+            wrapper_to_del (callable): wrapped handler to be removed\n+\n+        Returns:\n+            (bool) True if one or more handlers were removed, otherwise False.\n+        \"\"\"\n+        found_handler = False\n+        for priority, handler in list(cls.fallback_handlers.items()):\n+            if handler == wrapper_to_del:\n+                found_handler = True\n+                del cls.fallback_handlers[priority]\n+\n+        if not found_handler:\n+            LOG.warning('No fallback matching {}'.format(wrapper_to_del))\n+        return found_handler\n \n     @classmethod\n     def remove_fallback(cls, handler_to_del):\n@@ -131,15 +159,27 @@\n \n         Arguments:\n             handler_to_del: reference to handler\n+        Returns:\n+            (bool) True if at least one handler was removed, otherwise False\n         \"\"\"\n-        for priority, handler in cls.fallback_handlers.items():\n-            if handler == handler_to_del:\n-                del cls.fallback_handlers[priority]\n-                return\n-        LOG.warning('Could not remove fallback!')\n+        # Find wrapper from handler or wrapper\n+        wrapper_to_del = None\n+        for h, w in cls.wrapper_map:\n+            if handler_to_del in (h, w):\n+                wrapper_to_del = w\n+                break\n+\n+        if wrapper_to_del:\n+            cls.wrapper_map.remove((h, w))\n+            remove_ok = cls._remove_registered_handler(wrapper_to_del)\n+        else:\n+            LOG.warning('Could not find matching fallback handler')\n+            remove_ok = False\n+        return remove_ok\n \n     def remove_instance_handlers(self):\n         \"\"\"Remove all fallback handlers registered by the fallback skill.\"\"\"\n+        self.log.info('Removing all handlers...')\n         while len(self.instance_fallback_handlers):\n             handler = self.instance_fallback_handlers.pop()\n             self.remove_fallback(handler)\n", "issue": "self.remove_fallback(handler) it does not work\ni need the remove.fallback function after recording in my wakeword skill. I acted according to instructions https://mycroft-ai.gitbook.io/docs/skill-development/skill-types/fallback-skill. however, I always get the message. \"mycroft.skills.fallback_skill:remove_fallback:139 | Could not remove fallback!\". the fallback function is retained and is not deactivated. During the skill shutdown, the function is executed, the error message remains and fallback is deactivated.\r\n\n", "before_files": [{"content": "# Copyright 2019 Mycroft AI Inc.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#    http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\"\"\"The fallback skill implements a special type of skill handling\nutterances not handled by the intent system.\n\"\"\"\nimport operator\nfrom mycroft.metrics import report_timing, Stopwatch\nfrom mycroft.util.log import LOG\n\n\nfrom .mycroft_skill import MycroftSkill, get_handler_name\n\n\nclass FallbackSkill(MycroftSkill):\n    \"\"\"Fallbacks come into play when no skill matches an Adapt or closely with\n    a Padatious intent.  All Fallback skills work together to give them a\n    view of the user's utterance.  Fallback handlers are called in an order\n    determined the priority provided when the the handler is registered.\n\n    ========   ========   ================================================\n    Priority   Who?       Purpose\n    ========   ========   ================================================\n       1-4     RESERVED   Unused for now, slot for pre-Padatious if needed\n         5     MYCROFT    Padatious near match (conf > 0.8)\n      6-88     USER       General\n        89     MYCROFT    Padatious loose match (conf > 0.5)\n     90-99     USER       Uncaught intents\n       100+    MYCROFT    Fallback Unknown or other future use\n    ========   ========   ================================================\n\n    Handlers with the numerically lowest priority are invoked first.\n    Multiple fallbacks can exist at the same priority, but no order is\n    guaranteed.\n\n    A Fallback can either observe or consume an utterance. A consumed\n    utterance will not be see by any other Fallback handlers.\n    \"\"\"\n    fallback_handlers = {}\n\n    def __init__(self, name=None, bus=None, use_settings=True):\n        super().__init__(name, bus, use_settings)\n\n        #  list of fallback handlers registered by this instance\n        self.instance_fallback_handlers = []\n\n    @classmethod\n    def make_intent_failure_handler(cls, bus):\n        \"\"\"Goes through all fallback handlers until one returns True\"\"\"\n\n        def handler(message):\n            # indicate fallback handling start\n            bus.emit(message.forward(\"mycroft.skill.handler.start\",\n                                     data={'handler': \"fallback\"}))\n\n            stopwatch = Stopwatch()\n            handler_name = None\n            with stopwatch:\n                for _, handler in sorted(cls.fallback_handlers.items(),\n                                         key=operator.itemgetter(0)):\n                    try:\n                        if handler(message):\n                            #  indicate completion\n                            handler_name = get_handler_name(handler)\n                            bus.emit(message.forward(\n                                     'mycroft.skill.handler.complete',\n                                     data={'handler': \"fallback\",\n                                           \"fallback_handler\": handler_name}))\n                            break\n                    except Exception:\n                        LOG.exception('Exception in fallback.')\n                else:  # No fallback could handle the utterance\n                    bus.emit(message.forward('complete_intent_failure'))\n                    warning = \"No fallback could handle intent.\"\n                    LOG.warning(warning)\n                    #  indicate completion with exception\n                    bus.emit(message.forward('mycroft.skill.handler.complete',\n                                             data={'handler': \"fallback\",\n                                                   'exception': warning}))\n\n            # Send timing metric\n            if message.context.get('ident'):\n                ident = message.context['ident']\n                report_timing(ident, 'fallback_handler', stopwatch,\n                              {'handler': handler_name})\n\n        return handler\n\n    @classmethod\n    def _register_fallback(cls, handler, priority):\n        \"\"\"Register a function to be called as a general info fallback\n        Fallback should receive message and return\n        a boolean (True if succeeded or False if failed)\n\n        Lower priority gets run first\n        0 for high priority 100 for low priority\n        \"\"\"\n        while priority in cls.fallback_handlers:\n            priority += 1\n\n        cls.fallback_handlers[priority] = handler\n\n    def register_fallback(self, handler, priority):\n        \"\"\"Register a fallback with the list of fallback handlers and with the\n        list of handlers registered by this instance\n        \"\"\"\n\n        def wrapper(*args, **kwargs):\n            if handler(*args, **kwargs):\n                self.make_active()\n                return True\n            return False\n\n        self.instance_fallback_handlers.append(wrapper)\n        self._register_fallback(wrapper, priority)\n\n    @classmethod\n    def remove_fallback(cls, handler_to_del):\n        \"\"\"Remove a fallback handler.\n\n        Arguments:\n            handler_to_del: reference to handler\n        \"\"\"\n        for priority, handler in cls.fallback_handlers.items():\n            if handler == handler_to_del:\n                del cls.fallback_handlers[priority]\n                return\n        LOG.warning('Could not remove fallback!')\n\n    def remove_instance_handlers(self):\n        \"\"\"Remove all fallback handlers registered by the fallback skill.\"\"\"\n        while len(self.instance_fallback_handlers):\n            handler = self.instance_fallback_handlers.pop()\n            self.remove_fallback(handler)\n\n    def default_shutdown(self):\n        \"\"\"Remove all registered handlers and perform skill shutdown.\"\"\"\n        self.remove_instance_handlers()\n        super(FallbackSkill, self).default_shutdown()\n", "path": "mycroft/skills/fallback_skill.py"}], "after_files": [{"content": "# Copyright 2019 Mycroft AI Inc.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#    http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\"\"\"The fallback skill implements a special type of skill handling\nutterances not handled by the intent system.\n\"\"\"\nimport operator\nfrom mycroft.metrics import report_timing, Stopwatch\nfrom mycroft.util.log import LOG\n\n\nfrom .mycroft_skill import MycroftSkill, get_handler_name\n\n\nclass FallbackSkill(MycroftSkill):\n    \"\"\"Fallbacks come into play when no skill matches an Adapt or closely with\n    a Padatious intent.  All Fallback skills work together to give them a\n    view of the user's utterance.  Fallback handlers are called in an order\n    determined the priority provided when the the handler is registered.\n\n    ========   ========   ================================================\n    Priority   Who?       Purpose\n    ========   ========   ================================================\n       1-4     RESERVED   Unused for now, slot for pre-Padatious if needed\n         5     MYCROFT    Padatious near match (conf > 0.8)\n      6-88     USER       General\n        89     MYCROFT    Padatious loose match (conf > 0.5)\n     90-99     USER       Uncaught intents\n       100+    MYCROFT    Fallback Unknown or other future use\n    ========   ========   ================================================\n\n    Handlers with the numerically lowest priority are invoked first.\n    Multiple fallbacks can exist at the same priority, but no order is\n    guaranteed.\n\n    A Fallback can either observe or consume an utterance. A consumed\n    utterance will not be see by any other Fallback handlers.\n    \"\"\"\n    fallback_handlers = {}\n    wrapper_map = []  # Map containing (handler, wrapper) tuples\n\n    def __init__(self, name=None, bus=None, use_settings=True):\n        super().__init__(name, bus, use_settings)\n\n        #  list of fallback handlers registered by this instance\n        self.instance_fallback_handlers = []\n\n    @classmethod\n    def make_intent_failure_handler(cls, bus):\n        \"\"\"Goes through all fallback handlers until one returns True\"\"\"\n\n        def handler(message):\n            # indicate fallback handling start\n            bus.emit(message.forward(\"mycroft.skill.handler.start\",\n                                     data={'handler': \"fallback\"}))\n\n            stopwatch = Stopwatch()\n            handler_name = None\n            with stopwatch:\n                for _, handler in sorted(cls.fallback_handlers.items(),\n                                         key=operator.itemgetter(0)):\n                    try:\n                        if handler(message):\n                            #  indicate completion\n                            handler_name = get_handler_name(handler)\n                            bus.emit(message.forward(\n                                     'mycroft.skill.handler.complete',\n                                     data={'handler': \"fallback\",\n                                           \"fallback_handler\": handler_name}))\n                            break\n                    except Exception:\n                        LOG.exception('Exception in fallback.')\n                else:  # No fallback could handle the utterance\n                    bus.emit(message.forward('complete_intent_failure'))\n                    warning = \"No fallback could handle intent.\"\n                    LOG.warning(warning)\n                    #  indicate completion with exception\n                    bus.emit(message.forward('mycroft.skill.handler.complete',\n                                             data={'handler': \"fallback\",\n                                                   'exception': warning}))\n\n            # Send timing metric\n            if message.context.get('ident'):\n                ident = message.context['ident']\n                report_timing(ident, 'fallback_handler', stopwatch,\n                              {'handler': handler_name})\n\n        return handler\n\n    @classmethod\n    def _register_fallback(cls, handler, wrapper, priority):\n        \"\"\"Register a function to be called as a general info fallback\n        Fallback should receive message and return\n        a boolean (True if succeeded or False if failed)\n\n        Lower priority gets run first\n        0 for high priority 100 for low priority\n\n        Arguments:\n            handler (callable): original handler, used as a reference when\n                                removing\n            wrapper (callable): wrapped version of handler\n            priority (int): fallback priority\n        \"\"\"\n        while priority in cls.fallback_handlers:\n            priority += 1\n\n        cls.fallback_handlers[priority] = wrapper\n        cls.wrapper_map.append((handler, wrapper))\n\n    def register_fallback(self, handler, priority):\n        \"\"\"Register a fallback with the list of fallback handlers and with the\n        list of handlers registered by this instance\n        \"\"\"\n\n        def wrapper(*args, **kwargs):\n            if handler(*args, **kwargs):\n                self.make_active()\n                return True\n            return False\n\n        self.instance_fallback_handlers.append(handler)\n        self._register_fallback(handler, wrapper, priority)\n\n    @classmethod\n    def _remove_registered_handler(cls, wrapper_to_del):\n        \"\"\"Remove a registered wrapper.\n\n        Arguments:\n            wrapper_to_del (callable): wrapped handler to be removed\n\n        Returns:\n            (bool) True if one or more handlers were removed, otherwise False.\n        \"\"\"\n        found_handler = False\n        for priority, handler in list(cls.fallback_handlers.items()):\n            if handler == wrapper_to_del:\n                found_handler = True\n                del cls.fallback_handlers[priority]\n\n        if not found_handler:\n            LOG.warning('No fallback matching {}'.format(wrapper_to_del))\n        return found_handler\n\n    @classmethod\n    def remove_fallback(cls, handler_to_del):\n        \"\"\"Remove a fallback handler.\n\n        Arguments:\n            handler_to_del: reference to handler\n        Returns:\n            (bool) True if at least one handler was removed, otherwise False\n        \"\"\"\n        # Find wrapper from handler or wrapper\n        wrapper_to_del = None\n        for h, w in cls.wrapper_map:\n            if handler_to_del in (h, w):\n                wrapper_to_del = w\n                break\n\n        if wrapper_to_del:\n            cls.wrapper_map.remove((h, w))\n            remove_ok = cls._remove_registered_handler(wrapper_to_del)\n        else:\n            LOG.warning('Could not find matching fallback handler')\n            remove_ok = False\n        return remove_ok\n\n    def remove_instance_handlers(self):\n        \"\"\"Remove all fallback handlers registered by the fallback skill.\"\"\"\n        self.log.info('Removing all handlers...')\n        while len(self.instance_fallback_handlers):\n            handler = self.instance_fallback_handlers.pop()\n            self.remove_fallback(handler)\n\n    def default_shutdown(self):\n        \"\"\"Remove all registered handlers and perform skill shutdown.\"\"\"\n        self.remove_instance_handlers()\n        super(FallbackSkill, self).default_shutdown()\n", "path": "mycroft/skills/fallback_skill.py"}]}