prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  Invert constraints
  I can imagine situations where it would be useful to be able to invert constraints so that they do the opposite of what they are designed to do.
  
  ```python
  from opsdroid.skill import Skill
  from opsdroid.matchers import match_regex
  from opsdroid.constraints import constrain_users
  
  class MySkill(Skill):
  
      @match_regex(r'hi')
      @constrain_users(['alice', 'bob'], invert=True)
      async def hello(self, message):
          """Says 'Hey' to anyone EXCEPT 'alice' and 'bob'."""
          await message.respond('Hey')
  ```
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `opsdroid/constraints.py`
  Content:
  ```
  1 """Decorator functions to use when creating skill modules.
  2 
  3 These decorators are for specifying when a skill should not be called despite
  4 having a matcher which matches the current message.
  5 """
  6 
  7 import logging
  8 
  9 from opsdroid.helper import add_skill_attributes
  10 
  11 
  12 _LOGGER = logging.getLogger(__name__)
  13 
  14 
  15 def constrain_rooms(rooms):
  16     """Return room constraint decorator."""
  17 
  18     def constraint_decorator(func):
  19         """Add room constraint to skill."""
  20 
  21         def constraint_callback(message, rooms=rooms):
  22             """Check if the room is correct."""
  23             return message.target in rooms
  24 
  25         func = add_skill_attributes(func)
  26         func.constraints.append(constraint_callback)
  27         return func
  28 
  29     return constraint_decorator
  30 
  31 
  32 def constrain_users(users):
  33     """Return user constraint decorator."""
  34 
  35     def constraint_decorator(func):
  36         """Add user constraint to skill."""
  37 
  38         def constraint_callback(message, users=users):
  39             """Check if the user is correct."""
  40             return message.user in users
  41 
  42         func = add_skill_attributes(func)
  43         func.constraints.append(constraint_callback)
  44         return func
  45 
  46     return constraint_decorator
  47 
  48 
  49 def constrain_connectors(connectors):
  50     """Return connector constraint decorator."""
  51 
  52     def constraint_decorator(func):
  53         """Add connectors constraint to skill."""
  54 
  55         def constraint_callback(message, connectors=connectors):
  56             """Check if the connectors is correct."""
  57             return message.connector and (message.connector.name in connectors)
  58 
  59         func = add_skill_attributes(func)
  60         func.constraints.append(constraint_callback)
  61         return func
  62 
  63     return constraint_decorator
  64
  ```
  --- 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/opsdroid/constraints.py b/opsdroid/constraints.py
  --- a/opsdroid/constraints.py
  +++ b/opsdroid/constraints.py
  @@ -5,6 +5,7 @@
   """
   
   import logging
  +from functools import wraps
   
   from opsdroid.helper import add_skill_attributes
   
  @@ -12,7 +13,17 @@
   _LOGGER = logging.getLogger(__name__)
   
   
  -def constrain_rooms(rooms):
  +def invert_wrapper(func):
  +    """Inverts the result of a function."""
  +
  +    @wraps(func)
  +    def inverted_func(*args, **kwargs):
  +        return not func(*args, **kwargs)
  +
  +    return inverted_func
  +
  +
  +def constrain_rooms(rooms, invert=False):
       """Return room constraint decorator."""
   
       def constraint_decorator(func):
  @@ -23,13 +34,15 @@
               return message.target in rooms
   
           func = add_skill_attributes(func)
  +        if invert:
  +            constraint_callback = invert_wrapper(constraint_callback)
           func.constraints.append(constraint_callback)
           return func
   
       return constraint_decorator
   
   
  -def constrain_users(users):
  +def constrain_users(users, invert=False):
       """Return user constraint decorator."""
   
       def constraint_decorator(func):
  @@ -40,13 +53,15 @@
               return message.user in users
   
           func = add_skill_attributes(func)
  +        if invert:
  +            constraint_callback = invert_wrapper(constraint_callback)
           func.constraints.append(constraint_callback)
           return func
   
       return constraint_decorator
   
   
  -def constrain_connectors(connectors):
  +def constrain_connectors(connectors, invert=False):
       """Return connector constraint decorator."""
   
       def constraint_decorator(func):
  @@ -57,6 +72,8 @@
               return message.connector and (message.connector.name in connectors)
   
           func = add_skill_attributes(func)
  +        if invert:
  +            constraint_callback = invert_wrapper(constraint_callback)
           func.constraints.append(constraint_callback)
           return func
  
verification_info: {"golden_diff": "diff --git a/opsdroid/constraints.py b/opsdroid/constraints.py\n--- a/opsdroid/constraints.py\n+++ b/opsdroid/constraints.py\n@@ -5,6 +5,7 @@\n \"\"\"\n \n import logging\n+from functools import wraps\n \n from opsdroid.helper import add_skill_attributes\n \n@@ -12,7 +13,17 @@\n _LOGGER = logging.getLogger(__name__)\n \n \n-def constrain_rooms(rooms):\n+def invert_wrapper(func):\n+    \"\"\"Inverts the result of a function.\"\"\"\n+\n+    @wraps(func)\n+    def inverted_func(*args, **kwargs):\n+        return not func(*args, **kwargs)\n+\n+    return inverted_func\n+\n+\n+def constrain_rooms(rooms, invert=False):\n     \"\"\"Return room constraint decorator.\"\"\"\n \n     def constraint_decorator(func):\n@@ -23,13 +34,15 @@\n             return message.target in rooms\n \n         func = add_skill_attributes(func)\n+        if invert:\n+            constraint_callback = invert_wrapper(constraint_callback)\n         func.constraints.append(constraint_callback)\n         return func\n \n     return constraint_decorator\n \n \n-def constrain_users(users):\n+def constrain_users(users, invert=False):\n     \"\"\"Return user constraint decorator.\"\"\"\n \n     def constraint_decorator(func):\n@@ -40,13 +53,15 @@\n             return message.user in users\n \n         func = add_skill_attributes(func)\n+        if invert:\n+            constraint_callback = invert_wrapper(constraint_callback)\n         func.constraints.append(constraint_callback)\n         return func\n \n     return constraint_decorator\n \n \n-def constrain_connectors(connectors):\n+def constrain_connectors(connectors, invert=False):\n     \"\"\"Return connector constraint decorator.\"\"\"\n \n     def constraint_decorator(func):\n@@ -57,6 +72,8 @@\n             return message.connector and (message.connector.name in connectors)\n \n         func = add_skill_attributes(func)\n+        if invert:\n+            constraint_callback = invert_wrapper(constraint_callback)\n         func.constraints.append(constraint_callback)\n         return func\n", "issue": "Invert constraints\nI can imagine situations where it would be useful to be able to invert constraints so that they do the opposite of what they are designed to do.\r\n\r\n```python\r\nfrom opsdroid.skill import Skill\r\nfrom opsdroid.matchers import match_regex\r\nfrom opsdroid.constraints import constrain_users\r\n\r\nclass MySkill(Skill):\r\n\r\n    @match_regex(r'hi')\r\n    @constrain_users(['alice', 'bob'], invert=True)\r\n    async def hello(self, message):\r\n        \"\"\"Says 'Hey' to anyone EXCEPT 'alice' and 'bob'.\"\"\"\r\n        await message.respond('Hey')\r\n```\n", "before_files": [{"content": "\"\"\"Decorator functions to use when creating skill modules.\n\nThese decorators are for specifying when a skill should not be called despite\nhaving a matcher which matches the current message.\n\"\"\"\n\nimport logging\n\nfrom opsdroid.helper import add_skill_attributes\n\n\n_LOGGER = logging.getLogger(__name__)\n\n\ndef constrain_rooms(rooms):\n    \"\"\"Return room constraint decorator.\"\"\"\n\n    def constraint_decorator(func):\n        \"\"\"Add room constraint to skill.\"\"\"\n\n        def constraint_callback(message, rooms=rooms):\n            \"\"\"Check if the room is correct.\"\"\"\n            return message.target in rooms\n\n        func = add_skill_attributes(func)\n        func.constraints.append(constraint_callback)\n        return func\n\n    return constraint_decorator\n\n\ndef constrain_users(users):\n    \"\"\"Return user constraint decorator.\"\"\"\n\n    def constraint_decorator(func):\n        \"\"\"Add user constraint to skill.\"\"\"\n\n        def constraint_callback(message, users=users):\n            \"\"\"Check if the user is correct.\"\"\"\n            return message.user in users\n\n        func = add_skill_attributes(func)\n        func.constraints.append(constraint_callback)\n        return func\n\n    return constraint_decorator\n\n\ndef constrain_connectors(connectors):\n    \"\"\"Return connector constraint decorator.\"\"\"\n\n    def constraint_decorator(func):\n        \"\"\"Add connectors constraint to skill.\"\"\"\n\n        def constraint_callback(message, connectors=connectors):\n            \"\"\"Check if the connectors is correct.\"\"\"\n            return message.connector and (message.connector.name in connectors)\n\n        func = add_skill_attributes(func)\n        func.constraints.append(constraint_callback)\n        return func\n\n    return constraint_decorator\n", "path": "opsdroid/constraints.py"}], "after_files": [{"content": "\"\"\"Decorator functions to use when creating skill modules.\n\nThese decorators are for specifying when a skill should not be called despite\nhaving a matcher which matches the current message.\n\"\"\"\n\nimport logging\nfrom functools import wraps\n\nfrom opsdroid.helper import add_skill_attributes\n\n\n_LOGGER = logging.getLogger(__name__)\n\n\ndef invert_wrapper(func):\n    \"\"\"Inverts the result of a function.\"\"\"\n\n    @wraps(func)\n    def inverted_func(*args, **kwargs):\n        return not func(*args, **kwargs)\n\n    return inverted_func\n\n\ndef constrain_rooms(rooms, invert=False):\n    \"\"\"Return room constraint decorator.\"\"\"\n\n    def constraint_decorator(func):\n        \"\"\"Add room constraint to skill.\"\"\"\n\n        def constraint_callback(message, rooms=rooms):\n            \"\"\"Check if the room is correct.\"\"\"\n            return message.target in rooms\n\n        func = add_skill_attributes(func)\n        if invert:\n            constraint_callback = invert_wrapper(constraint_callback)\n        func.constraints.append(constraint_callback)\n        return func\n\n    return constraint_decorator\n\n\ndef constrain_users(users, invert=False):\n    \"\"\"Return user constraint decorator.\"\"\"\n\n    def constraint_decorator(func):\n        \"\"\"Add user constraint to skill.\"\"\"\n\n        def constraint_callback(message, users=users):\n            \"\"\"Check if the user is correct.\"\"\"\n            return message.user in users\n\n        func = add_skill_attributes(func)\n        if invert:\n            constraint_callback = invert_wrapper(constraint_callback)\n        func.constraints.append(constraint_callback)\n        return func\n\n    return constraint_decorator\n\n\ndef constrain_connectors(connectors, invert=False):\n    \"\"\"Return connector constraint decorator.\"\"\"\n\n    def constraint_decorator(func):\n        \"\"\"Add connectors constraint to skill.\"\"\"\n\n        def constraint_callback(message, connectors=connectors):\n            \"\"\"Check if the connectors is correct.\"\"\"\n            return message.connector and (message.connector.name in connectors)\n\n        func = add_skill_attributes(func)\n        if invert:\n            constraint_callback = invert_wrapper(constraint_callback)\n        func.constraints.append(constraint_callback)\n        return func\n\n    return constraint_decorator\n", "path": "opsdroid/constraints.py"}]}