prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  [V3 Context] Handle DMs properly during send_interactive
  (*forwarded from @palmtree5*)
  
  ### Type:
  
  - Bug
  
  ### Brief description of the problem
  When a user in DM types `more` during a case of `ctx.send_interactive` (for example, a long response to `[p]debug`), an error occurs.
  
  ### Expected behavior
  When a user types `more`, the bot's message *"type `more` to continue"* should be deleted.
  
  ### Actual behavior
  ```py
  Exception in command 'debug'
  Traceback (most recent call last):
    File "/home/palm/redv3/lib/python3.5/site-packages/discord/ext/commands/core.py", line 62, in wrapped
      ret = yield from coro(*args, **kwargs)
    File "/home/palm/redv3/lib/python3.5/site-packages/redbot/core/dev_commands.py", line 124, in debug
      await ctx.send_interactive(self.get_pages(result), box_lang="py")
    File "/home/palm/redv3/lib/python3.5/site-packages/redbot/core/context.py", line 120, in send_interactive
      await self.channel.delete_messages((query, resp))
  AttributeError: 'DMChannel' object has no attribute 'delete_messages'
  
  The above exception was the direct cause of the following exception:
  
  Traceback (most recent call last):
    File "/home/palm/redv3/lib/python3.5/site-packages/discord/ext/commands/bot.py", line 886, in invoke
      yield from ctx.command.invoke(ctx)
    File "/home/palm/redv3/lib/python3.5/site-packages/discord/ext/commands/core.py", line 489, in invoke
      yield from injected(*ctx.args, **ctx.kwargs)
    File "/home/palm/redv3/lib/python3.5/site-packages/discord/ext/commands/core.py", line 71, in wrapped
      raise CommandInvokeError(e) from e
  discord.ext.commands.errors.CommandInvokeError: Command raised an exception: AttributeError: 'DMChannel' object has no attribute 'delete_messages'
  ```
  
  ### Steps to reproduce
  
  1. Open a DM with the bot
  2. Do `[p]debug dir(bot)`
  3. Type `more` when queried
  
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `redbot/core/context.py`
  Content:
  ```
  1 """
  2 The purpose of this module is to allow for Red to further customise the command
  3 invocation context provided by discord.py.
  4 """
  5 import asyncio
  6 from typing import Iterable, List
  7 
  8 import discord
  9 from discord.ext import commands
  10 
  11 from redbot.core.utils.chat_formatting import box
  12 
  13 __all__ = ["RedContext"]
  14 
  15 TICK = "\N{WHITE HEAVY CHECK MARK}"
  16 
  17 
  18 class RedContext(commands.Context):
  19     """Command invocation context for Red.
  20 
  21     All context passed into commands will be of this type.
  22 
  23     This class inherits from `commands.Context <discord.ext.commands.Context>`.
  24     """
  25 
  26     async def send_help(self) -> List[discord.Message]:
  27         """Send the command help message.
  28 
  29         Returns
  30         -------
  31         `list` of `discord.Message`
  32             A list of help messages which were sent to the user.
  33 
  34         """
  35         command = self.invoked_subcommand or self.command
  36         embeds = await self.bot.formatter.format_help_for(self, command)
  37         destination = self
  38         ret = []
  39         for embed in embeds:
  40             try:
  41                 m = await destination.send(embed=embed)
  42             except discord.HTTPException:
  43                 destination = self.author
  44                 m = await destination.send(embed=embed)
  45             ret.append(m)
  46 
  47         return ret
  48 
  49     async def tick(self) -> bool:
  50         """Add a tick reaction to the command message.
  51 
  52         Returns
  53         -------
  54         bool
  55             :code:`True` if adding the reaction succeeded.
  56 
  57         """
  58         try:
  59             await self.message.add_reaction(TICK)
  60         except discord.HTTPException:
  61             return False
  62         else:
  63             return True
  64 
  65     async def send_interactive(self,
  66                                messages: Iterable[str],
  67                                box_lang: str=None,
  68                                timeout: int=15) -> List[discord.Message]:
  69         """Send multiple messages interactively.
  70 
  71         The user will be prompted for whether or not they would like to view
  72         the next message, one at a time. They will also be notified of how
  73         many messages are remaining on each prompt.
  74 
  75         Parameters
  76         ----------
  77         messages : `iterable` of `str`
  78             The messages to send.
  79         box_lang : str
  80             If specified, each message will be contained within a codeblock of
  81             this language.
  82         timeout : int
  83             How long the user has to respond to the prompt before it times out.
  84             After timing out, the bot deletes its prompt message.
  85 
  86         """
  87         messages = tuple(messages)
  88         ret = []
  89 
  90         more_check = lambda m: (m.author == self.author and
  91                                 m.channel == self.channel and
  92                                 m.content.lower() == "more")
  93 
  94         for idx, page in enumerate(messages, 1):
  95             if box_lang is None:
  96                 msg = await self.send(page)
  97             else:
  98                 msg = await self.send(box(page, lang=box_lang))
  99             ret.append(msg)
  100             n_remaining = len(messages) - idx
  101             if n_remaining > 0:
  102                 if n_remaining == 1:
  103                     plural = ""
  104                     is_are = "is"
  105                 else:
  106                     plural = "s"
  107                     is_are = "are"
  108                 query = await self.send(
  109                     "There {} still {} message{} remaining. "
  110                     "Type `more` to continue."
  111                     "".format(is_are, n_remaining, plural))
  112                 try:
  113                     resp = await self.bot.wait_for(
  114                         'message', check=more_check, timeout=timeout)
  115                 except asyncio.TimeoutError:
  116                     await query.delete()
  117                     break
  118                 else:
  119                     try:
  120                         await self.channel.delete_messages((query, resp))
  121                     except discord.HTTPException:
  122                         # In case the bot can't delete other users' messages,
  123                         # or is not a bot account
  124                         await query.delete()
  125         return ret
  126
  ```
  --- 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/redbot/core/context.py b/redbot/core/context.py
  --- a/redbot/core/context.py
  +++ b/redbot/core/context.py
  @@ -118,8 +118,9 @@
                   else:
                       try:
                           await self.channel.delete_messages((query, resp))
  -                    except discord.HTTPException:
  +                    except (discord.HTTPException, AttributeError):
                           # In case the bot can't delete other users' messages,
                           # or is not a bot account
  +                        # or chanel is a DM
                           await query.delete()
           return ret
  
verification_info: {"golden_diff": "diff --git a/redbot/core/context.py b/redbot/core/context.py\n--- a/redbot/core/context.py\n+++ b/redbot/core/context.py\n@@ -118,8 +118,9 @@\n                 else:\n                     try:\n                         await self.channel.delete_messages((query, resp))\n-                    except discord.HTTPException:\n+                    except (discord.HTTPException, AttributeError):\n                         # In case the bot can't delete other users' messages,\n                         # or is not a bot account\n+                        # or chanel is a DM\n                         await query.delete()\n         return ret\n", "issue": "[V3 Context] Handle DMs properly during send_interactive\n(*forwarded from @palmtree5*)\r\n\r\n### Type:\r\n\r\n- Bug\r\n\r\n### Brief description of the problem\r\nWhen a user in DM types `more` during a case of `ctx.send_interactive` (for example, a long response to `[p]debug`), an error occurs.\r\n\r\n### Expected behavior\r\nWhen a user types `more`, the bot's message *\"type `more` to continue\"* should be deleted.\r\n\r\n### Actual behavior\r\n```py\r\nException in command 'debug'\r\nTraceback (most recent call last):\r\n  File \"/home/palm/redv3/lib/python3.5/site-packages/discord/ext/commands/core.py\", line 62, in wrapped\r\n    ret = yield from coro(*args, **kwargs)\r\n  File \"/home/palm/redv3/lib/python3.5/site-packages/redbot/core/dev_commands.py\", line 124, in debug\r\n    await ctx.send_interactive(self.get_pages(result), box_lang=\"py\")\r\n  File \"/home/palm/redv3/lib/python3.5/site-packages/redbot/core/context.py\", line 120, in send_interactive\r\n    await self.channel.delete_messages((query, resp))\r\nAttributeError: 'DMChannel' object has no attribute 'delete_messages'\r\n\r\nThe above exception was the direct cause of the following exception:\r\n\r\nTraceback (most recent call last):\r\n  File \"/home/palm/redv3/lib/python3.5/site-packages/discord/ext/commands/bot.py\", line 886, in invoke\r\n    yield from ctx.command.invoke(ctx)\r\n  File \"/home/palm/redv3/lib/python3.5/site-packages/discord/ext/commands/core.py\", line 489, in invoke\r\n    yield from injected(*ctx.args, **ctx.kwargs)\r\n  File \"/home/palm/redv3/lib/python3.5/site-packages/discord/ext/commands/core.py\", line 71, in wrapped\r\n    raise CommandInvokeError(e) from e\r\ndiscord.ext.commands.errors.CommandInvokeError: Command raised an exception: AttributeError: 'DMChannel' object has no attribute 'delete_messages'\r\n```\r\n\r\n### Steps to reproduce\r\n\r\n1. Open a DM with the bot\r\n2. Do `[p]debug dir(bot)`\r\n3. Type `more` when queried\r\n\n", "before_files": [{"content": "\"\"\"\nThe purpose of this module is to allow for Red to further customise the command\ninvocation context provided by discord.py.\n\"\"\"\nimport asyncio\nfrom typing import Iterable, List\n\nimport discord\nfrom discord.ext import commands\n\nfrom redbot.core.utils.chat_formatting import box\n\n__all__ = [\"RedContext\"]\n\nTICK = \"\\N{WHITE HEAVY CHECK MARK}\"\n\n\nclass RedContext(commands.Context):\n    \"\"\"Command invocation context for Red.\n\n    All context passed into commands will be of this type.\n\n    This class inherits from `commands.Context <discord.ext.commands.Context>`.\n    \"\"\"\n\n    async def send_help(self) -> List[discord.Message]:\n        \"\"\"Send the command help message.\n\n        Returns\n        -------\n        `list` of `discord.Message`\n            A list of help messages which were sent to the user.\n\n        \"\"\"\n        command = self.invoked_subcommand or self.command\n        embeds = await self.bot.formatter.format_help_for(self, command)\n        destination = self\n        ret = []\n        for embed in embeds:\n            try:\n                m = await destination.send(embed=embed)\n            except discord.HTTPException:\n                destination = self.author\n                m = await destination.send(embed=embed)\n            ret.append(m)\n\n        return ret\n\n    async def tick(self) -> bool:\n        \"\"\"Add a tick reaction to the command message.\n\n        Returns\n        -------\n        bool\n            :code:`True` if adding the reaction succeeded.\n\n        \"\"\"\n        try:\n            await self.message.add_reaction(TICK)\n        except discord.HTTPException:\n            return False\n        else:\n            return True\n\n    async def send_interactive(self,\n                               messages: Iterable[str],\n                               box_lang: str=None,\n                               timeout: int=15) -> List[discord.Message]:\n        \"\"\"Send multiple messages interactively.\n\n        The user will be prompted for whether or not they would like to view\n        the next message, one at a time. They will also be notified of how\n        many messages are remaining on each prompt.\n\n        Parameters\n        ----------\n        messages : `iterable` of `str`\n            The messages to send.\n        box_lang : str\n            If specified, each message will be contained within a codeblock of\n            this language.\n        timeout : int\n            How long the user has to respond to the prompt before it times out.\n            After timing out, the bot deletes its prompt message.\n\n        \"\"\"\n        messages = tuple(messages)\n        ret = []\n\n        more_check = lambda m: (m.author == self.author and\n                                m.channel == self.channel and\n                                m.content.lower() == \"more\")\n\n        for idx, page in enumerate(messages, 1):\n            if box_lang is None:\n                msg = await self.send(page)\n            else:\n                msg = await self.send(box(page, lang=box_lang))\n            ret.append(msg)\n            n_remaining = len(messages) - idx\n            if n_remaining > 0:\n                if n_remaining == 1:\n                    plural = \"\"\n                    is_are = \"is\"\n                else:\n                    plural = \"s\"\n                    is_are = \"are\"\n                query = await self.send(\n                    \"There {} still {} message{} remaining. \"\n                    \"Type `more` to continue.\"\n                    \"\".format(is_are, n_remaining, plural))\n                try:\n                    resp = await self.bot.wait_for(\n                        'message', check=more_check, timeout=timeout)\n                except asyncio.TimeoutError:\n                    await query.delete()\n                    break\n                else:\n                    try:\n                        await self.channel.delete_messages((query, resp))\n                    except discord.HTTPException:\n                        # In case the bot can't delete other users' messages,\n                        # or is not a bot account\n                        await query.delete()\n        return ret\n", "path": "redbot/core/context.py"}], "after_files": [{"content": "\"\"\"\nThe purpose of this module is to allow for Red to further customise the command\ninvocation context provided by discord.py.\n\"\"\"\nimport asyncio\nfrom typing import Iterable, List\n\nimport discord\nfrom discord.ext import commands\n\nfrom redbot.core.utils.chat_formatting import box\n\n__all__ = [\"RedContext\"]\n\nTICK = \"\\N{WHITE HEAVY CHECK MARK}\"\n\n\nclass RedContext(commands.Context):\n    \"\"\"Command invocation context for Red.\n\n    All context passed into commands will be of this type.\n\n    This class inherits from `commands.Context <discord.ext.commands.Context>`.\n    \"\"\"\n\n    async def send_help(self) -> List[discord.Message]:\n        \"\"\"Send the command help message.\n\n        Returns\n        -------\n        `list` of `discord.Message`\n            A list of help messages which were sent to the user.\n\n        \"\"\"\n        command = self.invoked_subcommand or self.command\n        embeds = await self.bot.formatter.format_help_for(self, command)\n        destination = self\n        ret = []\n        for embed in embeds:\n            try:\n                m = await destination.send(embed=embed)\n            except discord.HTTPException:\n                destination = self.author\n                m = await destination.send(embed=embed)\n            ret.append(m)\n\n        return ret\n\n    async def tick(self) -> bool:\n        \"\"\"Add a tick reaction to the command message.\n\n        Returns\n        -------\n        bool\n            :code:`True` if adding the reaction succeeded.\n\n        \"\"\"\n        try:\n            await self.message.add_reaction(TICK)\n        except discord.HTTPException:\n            return False\n        else:\n            return True\n\n    async def send_interactive(self,\n                               messages: Iterable[str],\n                               box_lang: str=None,\n                               timeout: int=15) -> List[discord.Message]:\n        \"\"\"Send multiple messages interactively.\n\n        The user will be prompted for whether or not they would like to view\n        the next message, one at a time. They will also be notified of how\n        many messages are remaining on each prompt.\n\n        Parameters\n        ----------\n        messages : `iterable` of `str`\n            The messages to send.\n        box_lang : str\n            If specified, each message will be contained within a codeblock of\n            this language.\n        timeout : int\n            How long the user has to respond to the prompt before it times out.\n            After timing out, the bot deletes its prompt message.\n\n        \"\"\"\n        messages = tuple(messages)\n        ret = []\n\n        more_check = lambda m: (m.author == self.author and\n                                m.channel == self.channel and\n                                m.content.lower() == \"more\")\n\n        for idx, page in enumerate(messages, 1):\n            if box_lang is None:\n                msg = await self.send(page)\n            else:\n                msg = await self.send(box(page, lang=box_lang))\n            ret.append(msg)\n            n_remaining = len(messages) - idx\n            if n_remaining > 0:\n                if n_remaining == 1:\n                    plural = \"\"\n                    is_are = \"is\"\n                else:\n                    plural = \"s\"\n                    is_are = \"are\"\n                query = await self.send(\n                    \"There {} still {} message{} remaining. \"\n                    \"Type `more` to continue.\"\n                    \"\".format(is_are, n_remaining, plural))\n                try:\n                    resp = await self.bot.wait_for(\n                        'message', check=more_check, timeout=timeout)\n                except asyncio.TimeoutError:\n                    await query.delete()\n                    break\n                else:\n                    try:\n                        await self.channel.delete_messages((query, resp))\n                    except (discord.HTTPException, AttributeError):\n                        # In case the bot can't delete other users' messages,\n                        # or is not a bot account\n                        # or chanel is a DM\n                        await query.delete()\n        return ret\n", "path": "redbot/core/context.py"}]}