prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  Upgrade redis database backend to use aioredis v2
  Looks like v2 of `aioredis` is out and has breaking changes which affect us. In #1809 I've pinned us to v1 for now but we should upgrade things to work with v2.
  
  Specifically importing the parser fails
  
  https://github.com/opsdroid/opsdroid/blob/a45490d1bdceca39b49880e20262b55ea0be101d/opsdroid/database/redis/__init__.py#L6
  
  ```python-traceback
     ImportError while importing test module '/home/runner/work/opsdroid/opsdroid/opsdroid/database/redis/tests/test_redis.py'.
    Hint: make sure your test modules/packages have valid Python names.
    Traceback:
    /opt/hostedtoolcache/Python/3.7.11/x64/lib/python3.7/importlib/__init__.py:127: in import_module
        return _bootstrap._gcd_import(name[level:], package, level)
    opsdroid/database/redis/tests/test_redis.py:8: in <module>
        from opsdroid.database.redis import RedisDatabase
    opsdroid/database/redis/__init__.py:6: in <module>
        from aioredis import parser
    E   ImportError: cannot import name 'parser' from 'aioredis' (/home/runner/work/opsdroid/opsdroid/.tox/py37-e2e/lib/python3.7/site-packages/aioredis/__init__.py)
  ```
  
  --- 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/database/redis/__init__.py`
  Content:
  ```
  1 """Module for storing data within Redis."""
  2 import json
  3 import logging
  4 
  5 import aioredis
  6 from aioredis import parser
  7 from voluptuous import Any
  8 
  9 from opsdroid.database import Database
  10 from opsdroid.helper import JSONEncoder, JSONDecoder
  11 
  12 _LOGGER = logging.getLogger(__name__)
  13 CONFIG_SCHEMA = {"host": str, "port": Any(int, str), "database": int, "password": str}
  14 
  15 
  16 class RedisDatabase(Database):
  17     """Database class for storing data within a Redis instance."""
  18 
  19     def __init__(self, config, opsdroid=None):
  20         """Initialise the redis database.
  21 
  22         Set basic properties of the database. Initialise properties like
  23         name, connection arguments, database file, table name and config.
  24 
  25         Args:
  26             config (dict): The configuration of the database which consists
  27                            of `file` and `table` name of the sqlite database
  28                            specified in `configuration.yaml` file.
  29             opsdroid (OpsDroid): An instance of opsdroid.core.
  30 
  31         """
  32         super().__init__(config, opsdroid=opsdroid)
  33         self.config = config
  34         self.client = None
  35         self.host = self.config.get("host", "localhost")
  36         self.port = self.config.get("port", 6379)
  37         self.database = self.config.get("database", 0)
  38         self.password = self.config.get("password", None)
  39         _LOGGER.debug(_("Loaded Redis database connector."))
  40 
  41     async def connect(self):
  42         """Connect to the database.
  43 
  44         This method will connect to a Redis database. By default it will
  45         connect to Redis on localhost on port 6379
  46 
  47         """
  48         try:
  49             self.client = await aioredis.create_pool(
  50                 address=(self.host, int(self.port)),
  51                 db=self.database,
  52                 password=self.password,
  53                 parser=parser.PyReader,
  54             )
  55 
  56             _LOGGER.info(
  57                 _("Connected to Redis database %s from %s on port %s."),
  58                 self.database,
  59                 self.host,
  60                 self.port,
  61             )
  62         except OSError:
  63             _LOGGER.warning(
  64                 _("Unable to connect to Redis database on address: %s port: %s."),
  65                 self.host,
  66                 self.port,
  67             )
  68 
  69     async def put(self, key, data):
  70         """Store the data object in Redis against the key.
  71 
  72         Args:
  73             key (string): The key to store the data object under.
  74             data (object): The data object to store.
  75 
  76         """
  77         if self.client:
  78             _LOGGER.debug(_("Putting %s into Redis."), key)
  79             await self.client.execute("SET", key, json.dumps(data, cls=JSONEncoder))
  80 
  81     async def get(self, key):
  82         """Get data from Redis for a given key.
  83 
  84         Args:
  85             key (string): The key to lookup in the database.
  86 
  87         Returns:
  88             object or None: The data object stored for that key, or None if no
  89                             object found for that key.
  90 
  91         """
  92         if self.client:
  93             _LOGGER.debug(_("Getting %s from Redis."), key)
  94             data = await self.client.execute("GET", key)
  95 
  96             if data:
  97                 return json.loads(data, object_hook=JSONDecoder())
  98 
  99             return None
  100 
  101     async def delete(self, key):
  102         """Delete data from Redis for a given key.
  103 
  104         Args:
  105             key (string): The key to delete in the database.
  106 
  107         """
  108         if self.client:
  109             _LOGGER.debug(_("Deleting %s from Redis."), key)
  110             await self.client.execute("DEL", key)
  111 
  112     async def disconnect(self):
  113         """Disconnect from the database."""
  114         if self.client:
  115             self.client.close()
  116
  ```
  --- 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/database/redis/__init__.py b/opsdroid/database/redis/__init__.py
  --- a/opsdroid/database/redis/__init__.py
  +++ b/opsdroid/database/redis/__init__.py
  @@ -2,8 +2,7 @@
   import json
   import logging
   
  -import aioredis
  -from aioredis import parser
  +from aioredis import Redis
   from voluptuous import Any
   
   from opsdroid.database import Database
  @@ -46,12 +45,13 @@
   
           """
           try:
  -            self.client = await aioredis.create_pool(
  -                address=(self.host, int(self.port)),
  +            self.client = Redis(
  +                host=self.host,
  +                port=int(self.port),
                   db=self.database,
                   password=self.password,
  -                parser=parser.PyReader,
               )
  +            await self.client.ping()  # to actually initiate a connection
   
               _LOGGER.info(
                   _("Connected to Redis database %s from %s on port %s."),
  @@ -76,7 +76,9 @@
           """
           if self.client:
               _LOGGER.debug(_("Putting %s into Redis."), key)
  -            await self.client.execute("SET", key, json.dumps(data, cls=JSONEncoder))
  +            await self.client.execute_command(
  +                "SET", key, json.dumps(data, cls=JSONEncoder)
  +            )
   
       async def get(self, key):
           """Get data from Redis for a given key.
  @@ -91,7 +93,7 @@
           """
           if self.client:
               _LOGGER.debug(_("Getting %s from Redis."), key)
  -            data = await self.client.execute("GET", key)
  +            data = await self.client.execute_command("GET", key)
   
               if data:
                   return json.loads(data, object_hook=JSONDecoder())
  @@ -107,9 +109,9 @@
           """
           if self.client:
               _LOGGER.debug(_("Deleting %s from Redis."), key)
  -            await self.client.execute("DEL", key)
  +            await self.client.execute_command("DEL", key)
   
       async def disconnect(self):
           """Disconnect from the database."""
           if self.client:
  -            self.client.close()
  +            await self.client.close()
  
verification_info: {"golden_diff": "diff --git a/opsdroid/database/redis/__init__.py b/opsdroid/database/redis/__init__.py\n--- a/opsdroid/database/redis/__init__.py\n+++ b/opsdroid/database/redis/__init__.py\n@@ -2,8 +2,7 @@\n import json\n import logging\n \n-import aioredis\n-from aioredis import parser\n+from aioredis import Redis\n from voluptuous import Any\n \n from opsdroid.database import Database\n@@ -46,12 +45,13 @@\n \n         \"\"\"\n         try:\n-            self.client = await aioredis.create_pool(\n-                address=(self.host, int(self.port)),\n+            self.client = Redis(\n+                host=self.host,\n+                port=int(self.port),\n                 db=self.database,\n                 password=self.password,\n-                parser=parser.PyReader,\n             )\n+            await self.client.ping()  # to actually initiate a connection\n \n             _LOGGER.info(\n                 _(\"Connected to Redis database %s from %s on port %s.\"),\n@@ -76,7 +76,9 @@\n         \"\"\"\n         if self.client:\n             _LOGGER.debug(_(\"Putting %s into Redis.\"), key)\n-            await self.client.execute(\"SET\", key, json.dumps(data, cls=JSONEncoder))\n+            await self.client.execute_command(\n+                \"SET\", key, json.dumps(data, cls=JSONEncoder)\n+            )\n \n     async def get(self, key):\n         \"\"\"Get data from Redis for a given key.\n@@ -91,7 +93,7 @@\n         \"\"\"\n         if self.client:\n             _LOGGER.debug(_(\"Getting %s from Redis.\"), key)\n-            data = await self.client.execute(\"GET\", key)\n+            data = await self.client.execute_command(\"GET\", key)\n \n             if data:\n                 return json.loads(data, object_hook=JSONDecoder())\n@@ -107,9 +109,9 @@\n         \"\"\"\n         if self.client:\n             _LOGGER.debug(_(\"Deleting %s from Redis.\"), key)\n-            await self.client.execute(\"DEL\", key)\n+            await self.client.execute_command(\"DEL\", key)\n \n     async def disconnect(self):\n         \"\"\"Disconnect from the database.\"\"\"\n         if self.client:\n-            self.client.close()\n+            await self.client.close()\n", "issue": "Upgrade redis database backend to use aioredis v2\nLooks like v2 of `aioredis` is out and has breaking changes which affect us. In #1809 I've pinned us to v1 for now but we should upgrade things to work with v2.\r\n\r\nSpecifically importing the parser fails\r\n\r\nhttps://github.com/opsdroid/opsdroid/blob/a45490d1bdceca39b49880e20262b55ea0be101d/opsdroid/database/redis/__init__.py#L6\r\n\r\n```python-traceback\r\n   ImportError while importing test module '/home/runner/work/opsdroid/opsdroid/opsdroid/database/redis/tests/test_redis.py'.\r\n  Hint: make sure your test modules/packages have valid Python names.\r\n  Traceback:\r\n  /opt/hostedtoolcache/Python/3.7.11/x64/lib/python3.7/importlib/__init__.py:127: in import_module\r\n      return _bootstrap._gcd_import(name[level:], package, level)\r\n  opsdroid/database/redis/tests/test_redis.py:8: in <module>\r\n      from opsdroid.database.redis import RedisDatabase\r\n  opsdroid/database/redis/__init__.py:6: in <module>\r\n      from aioredis import parser\r\n  E   ImportError: cannot import name 'parser' from 'aioredis' (/home/runner/work/opsdroid/opsdroid/.tox/py37-e2e/lib/python3.7/site-packages/aioredis/__init__.py)\r\n```\n", "before_files": [{"content": "\"\"\"Module for storing data within Redis.\"\"\"\nimport json\nimport logging\n\nimport aioredis\nfrom aioredis import parser\nfrom voluptuous import Any\n\nfrom opsdroid.database import Database\nfrom opsdroid.helper import JSONEncoder, JSONDecoder\n\n_LOGGER = logging.getLogger(__name__)\nCONFIG_SCHEMA = {\"host\": str, \"port\": Any(int, str), \"database\": int, \"password\": str}\n\n\nclass RedisDatabase(Database):\n    \"\"\"Database class for storing data within a Redis instance.\"\"\"\n\n    def __init__(self, config, opsdroid=None):\n        \"\"\"Initialise the redis database.\n\n        Set basic properties of the database. Initialise properties like\n        name, connection arguments, database file, table name and config.\n\n        Args:\n            config (dict): The configuration of the database which consists\n                           of `file` and `table` name of the sqlite database\n                           specified in `configuration.yaml` file.\n            opsdroid (OpsDroid): An instance of opsdroid.core.\n\n        \"\"\"\n        super().__init__(config, opsdroid=opsdroid)\n        self.config = config\n        self.client = None\n        self.host = self.config.get(\"host\", \"localhost\")\n        self.port = self.config.get(\"port\", 6379)\n        self.database = self.config.get(\"database\", 0)\n        self.password = self.config.get(\"password\", None)\n        _LOGGER.debug(_(\"Loaded Redis database connector.\"))\n\n    async def connect(self):\n        \"\"\"Connect to the database.\n\n        This method will connect to a Redis database. By default it will\n        connect to Redis on localhost on port 6379\n\n        \"\"\"\n        try:\n            self.client = await aioredis.create_pool(\n                address=(self.host, int(self.port)),\n                db=self.database,\n                password=self.password,\n                parser=parser.PyReader,\n            )\n\n            _LOGGER.info(\n                _(\"Connected to Redis database %s from %s on port %s.\"),\n                self.database,\n                self.host,\n                self.port,\n            )\n        except OSError:\n            _LOGGER.warning(\n                _(\"Unable to connect to Redis database on address: %s port: %s.\"),\n                self.host,\n                self.port,\n            )\n\n    async def put(self, key, data):\n        \"\"\"Store the data object in Redis against the key.\n\n        Args:\n            key (string): The key to store the data object under.\n            data (object): The data object to store.\n\n        \"\"\"\n        if self.client:\n            _LOGGER.debug(_(\"Putting %s into Redis.\"), key)\n            await self.client.execute(\"SET\", key, json.dumps(data, cls=JSONEncoder))\n\n    async def get(self, key):\n        \"\"\"Get data from Redis for a given key.\n\n        Args:\n            key (string): The key to lookup in the database.\n\n        Returns:\n            object or None: The data object stored for that key, or None if no\n                            object found for that key.\n\n        \"\"\"\n        if self.client:\n            _LOGGER.debug(_(\"Getting %s from Redis.\"), key)\n            data = await self.client.execute(\"GET\", key)\n\n            if data:\n                return json.loads(data, object_hook=JSONDecoder())\n\n            return None\n\n    async def delete(self, key):\n        \"\"\"Delete data from Redis for a given key.\n\n        Args:\n            key (string): The key to delete in the database.\n\n        \"\"\"\n        if self.client:\n            _LOGGER.debug(_(\"Deleting %s from Redis.\"), key)\n            await self.client.execute(\"DEL\", key)\n\n    async def disconnect(self):\n        \"\"\"Disconnect from the database.\"\"\"\n        if self.client:\n            self.client.close()\n", "path": "opsdroid/database/redis/__init__.py"}], "after_files": [{"content": "\"\"\"Module for storing data within Redis.\"\"\"\nimport json\nimport logging\n\nfrom aioredis import Redis\nfrom voluptuous import Any\n\nfrom opsdroid.database import Database\nfrom opsdroid.helper import JSONEncoder, JSONDecoder\n\n_LOGGER = logging.getLogger(__name__)\nCONFIG_SCHEMA = {\"host\": str, \"port\": Any(int, str), \"database\": int, \"password\": str}\n\n\nclass RedisDatabase(Database):\n    \"\"\"Database class for storing data within a Redis instance.\"\"\"\n\n    def __init__(self, config, opsdroid=None):\n        \"\"\"Initialise the redis database.\n\n        Set basic properties of the database. Initialise properties like\n        name, connection arguments, database file, table name and config.\n\n        Args:\n            config (dict): The configuration of the database which consists\n                           of `file` and `table` name of the sqlite database\n                           specified in `configuration.yaml` file.\n            opsdroid (OpsDroid): An instance of opsdroid.core.\n\n        \"\"\"\n        super().__init__(config, opsdroid=opsdroid)\n        self.config = config\n        self.client = None\n        self.host = self.config.get(\"host\", \"localhost\")\n        self.port = self.config.get(\"port\", 6379)\n        self.database = self.config.get(\"database\", 0)\n        self.password = self.config.get(\"password\", None)\n        _LOGGER.debug(_(\"Loaded Redis database connector.\"))\n\n    async def connect(self):\n        \"\"\"Connect to the database.\n\n        This method will connect to a Redis database. By default it will\n        connect to Redis on localhost on port 6379\n\n        \"\"\"\n        try:\n            self.client = Redis(\n                host=self.host,\n                port=int(self.port),\n                db=self.database,\n                password=self.password,\n            )\n            await self.client.ping()  # to actually initiate a connection\n\n            _LOGGER.info(\n                _(\"Connected to Redis database %s from %s on port %s.\"),\n                self.database,\n                self.host,\n                self.port,\n            )\n        except OSError:\n            _LOGGER.warning(\n                _(\"Unable to connect to Redis database on address: %s port: %s.\"),\n                self.host,\n                self.port,\n            )\n\n    async def put(self, key, data):\n        \"\"\"Store the data object in Redis against the key.\n\n        Args:\n            key (string): The key to store the data object under.\n            data (object): The data object to store.\n\n        \"\"\"\n        if self.client:\n            _LOGGER.debug(_(\"Putting %s into Redis.\"), key)\n            await self.client.execute_command(\n                \"SET\", key, json.dumps(data, cls=JSONEncoder)\n            )\n\n    async def get(self, key):\n        \"\"\"Get data from Redis for a given key.\n\n        Args:\n            key (string): The key to lookup in the database.\n\n        Returns:\n            object or None: The data object stored for that key, or None if no\n                            object found for that key.\n\n        \"\"\"\n        if self.client:\n            _LOGGER.debug(_(\"Getting %s from Redis.\"), key)\n            data = await self.client.execute_command(\"GET\", key)\n\n            if data:\n                return json.loads(data, object_hook=JSONDecoder())\n\n            return None\n\n    async def delete(self, key):\n        \"\"\"Delete data from Redis for a given key.\n\n        Args:\n            key (string): The key to delete in the database.\n\n        \"\"\"\n        if self.client:\n            _LOGGER.debug(_(\"Deleting %s from Redis.\"), key)\n            await self.client.execute_command(\"DEL\", key)\n\n    async def disconnect(self):\n        \"\"\"Disconnect from the database.\"\"\"\n        if self.client:\n            await self.client.close()\n", "path": "opsdroid/database/redis/__init__.py"}]}