prompt: You will be provided with a partial code base and an issue statement explaining a problem to resolve.
  <issue>
  Delete messages when `!pypi` module is invalid
  When users use the `!pypi` command with an invalid module, you currently get a response saying `"Package could not be found."`. 
  
  What I'm proposing it that after a delay (I believe we have `bot.constants.RedirectOutput.delete_delay` for this) the bot should delete both its response and the invocation message, like [`!d` currently does](https://github.com/python-discord/bot/blob/master/bot/exts/info/doc.py#L363-L365).
  
  This would help reduce channel flooding when someone is trying to remember the name of a module, and since it's not a trivial change I'm happy to try and implement this myself if it's something we decide we want.
  
  </issue>
  <code>
  [start of bot/exts/info/pypi.py]
  1 import itertools
  2 import logging
  3 import random
  4 import re
  5 
  6 from discord import Embed
  7 from discord.ext.commands import Cog, Context, command
  8 from discord.utils import escape_markdown
  9 
  10 from bot.bot import Bot
  11 from bot.constants import Colours, NEGATIVE_REPLIES
  12 
  13 URL = "https://pypi.org/pypi/{package}/json"
  14 FIELDS = ("author", "requires_python", "summary", "license")
  15 PYPI_ICON = "https://cdn.discordapp.com/emojis/766274397257334814.png"
  16 
  17 PYPI_COLOURS = itertools.cycle((Colours.yellow, Colours.blue, Colours.white))
  18 
  19 ILLEGAL_CHARACTERS = re.compile(r"[^a-zA-Z0-9-.]+")
  20 
  21 log = logging.getLogger(__name__)
  22 
  23 
  24 class PyPi(Cog):
  25     """Cog for getting information about PyPi packages."""
  26 
  27     def __init__(self, bot: Bot):
  28         self.bot = bot
  29 
  30     @command(name="pypi", aliases=("package", "pack"))
  31     async def get_package_info(self, ctx: Context, package: str) -> None:
  32         """Provide information about a specific package from PyPI."""
  33         embed = Embed(
  34             title=random.choice(NEGATIVE_REPLIES),
  35             colour=Colours.soft_red
  36         )
  37         embed.set_thumbnail(url=PYPI_ICON)
  38 
  39         if (character := re.search(ILLEGAL_CHARACTERS, package)) is not None:
  40             embed.description = f"Illegal character passed into command: '{escape_markdown(character.group(0))}'"
  41             await ctx.send(embed=embed)
  42             return
  43 
  44         async with self.bot.http_session.get(URL.format(package=package)) as response:
  45             if response.status == 404:
  46                 embed.description = "Package could not be found."
  47 
  48             elif response.status == 200 and response.content_type == "application/json":
  49                 response_json = await response.json()
  50                 info = response_json["info"]
  51 
  52                 embed.title = f"{info['name']} v{info['version']}"
  53                 embed.url = info['package_url']
  54                 embed.colour = next(PYPI_COLOURS)
  55 
  56                 for field in FIELDS:
  57                     field_data = info[field]
  58 
  59                     # Field could be completely empty, in some cases can be a string with whitespaces, or None.
  60                     if field_data and not field_data.isspace():
  61                         if '\n' in field_data and field == "license":
  62                             field_data = field_data.split('\n')[0]
  63 
  64                         embed.add_field(
  65                             name=field.replace("_", " ").title(),
  66                             value=escape_markdown(field_data),
  67                             inline=False,
  68                         )
  69 
  70             else:
  71                 embed.description = "There was an error when fetching your PyPi package."
  72                 log.trace(f"Error when fetching PyPi package: {response.status}.")
  73 
  74         await ctx.send(embed=embed)
  75 
  76 
  77 def setup(bot: Bot) -> None:
  78     """Load the PyPi cog."""
  79     bot.add_cog(PyPi(bot))
  80
  [end of bot/exts/info/pypi.py]
  </code>
  
  I need you to solve this issue by generating a single patch file that I can apply directly to this repository using git apply. Please respond with a single patch file in the following format.
  <patch>
  diff --git a/file.py b/file.py
  --- a/file.py
  +++ b/file.py
  @@ -1,27 +1,35 @@
   def euclidean(a, b):
  -    while b:
  -        a, b = b, a % b
  -    return a
  +    if b == 0:
  +        return a
  +    return euclidean(b, a % b)
   
   
   def bresenham(x0, y0, x1, y1):
       points = []
       dx = abs(x1 - x0)
       dy = abs(y1 - y0)
  -    sx = 1 if x0 < x1 else -1
  -    sy = 1 if y0 < y1 else -1
  -    err = dx - dy
  +    x, y = x0, y0
  +    sx = -1 if x0 > x1 else 1
  +    sy = -1 if y0 > y1 else 1
   
  -    while True:
  -        points.append((x0, y0))
  -        if x0 == x1 and y0 == y1:
  -            break
  -        e2 = 2 * err
  -        if e2 > -dy:
  -            err -= dy
  -            x0 += sx
  -        if e2 < dx:
  -            err += dx
  -            y0 += sy
  +    if dx > dy:
  +        err = dx / 2.0
  +        while x != x1:
  +            points.append((x, y))
  +            err -= dy
  +            if err < 0:
  +                y += sy
  +                err += dx
  +            x += sx
  +    else:
  +        err = dy / 2.0
  +        while y != y1:
  +            points.append((x, y))
  +            err -= dx
  +            if err < 0:
  +                x += sx
  +                err += dy
  +            y += sy
  +
  +    points.append((x, y))
       return points
  
  </patch>
golden_diff: diff --git a/bot/exts/info/pypi.py b/bot/exts/info/pypi.py
  --- a/bot/exts/info/pypi.py
  +++ b/bot/exts/info/pypi.py
  @@ -8,7 +8,7 @@
   from discord.utils import escape_markdown
   
   from bot.bot import Bot
  -from bot.constants import Colours, NEGATIVE_REPLIES
  +from bot.constants import Colours, NEGATIVE_REPLIES, RedirectOutput
   
   URL = "https://pypi.org/pypi/{package}/json"
   FIELDS = ("author", "requires_python", "summary", "license")
  @@ -17,6 +17,7 @@
   PYPI_COLOURS = itertools.cycle((Colours.yellow, Colours.blue, Colours.white))
   
   ILLEGAL_CHARACTERS = re.compile(r"[^a-zA-Z0-9-.]+")
  +INVALID_INPUT_DELETE_DELAY = RedirectOutput.delete_delay
   
   log = logging.getLogger(__name__)
   
  @@ -36,42 +37,49 @@
           )
           embed.set_thumbnail(url=PYPI_ICON)
   
  +        error = True
  +
           if (character := re.search(ILLEGAL_CHARACTERS, package)) is not None:
               embed.description = f"Illegal character passed into command: '{escape_markdown(character.group(0))}'"
  -            await ctx.send(embed=embed)
  -            return
   
  -        async with self.bot.http_session.get(URL.format(package=package)) as response:
  -            if response.status == 404:
  -                embed.description = "Package could not be found."
  +        else:
  +            async with self.bot.http_session.get(URL.format(package=package)) as response:
  +                if response.status == 404:
  +                    embed.description = "Package could not be found."
   
  -            elif response.status == 200 and response.content_type == "application/json":
  -                response_json = await response.json()
  -                info = response_json["info"]
  +                elif response.status == 200 and response.content_type == "application/json":
  +                    response_json = await response.json()
  +                    info = response_json["info"]
   
  -                embed.title = f"{info['name']} v{info['version']}"
  -                embed.url = info['package_url']
  -                embed.colour = next(PYPI_COLOURS)
  +                    embed.title = f"{info['name']} v{info['version']}"
  +                    embed.url = info['package_url']
  +                    embed.colour = next(PYPI_COLOURS)
   
  -                for field in FIELDS:
  -                    field_data = info[field]
  +                    for field in FIELDS:
  +                        field_data = info[field]
   
  -                    # Field could be completely empty, in some cases can be a string with whitespaces, or None.
  -                    if field_data and not field_data.isspace():
  -                        if '\n' in field_data and field == "license":
  -                            field_data = field_data.split('\n')[0]
  +                        # Field could be completely empty, in some cases can be a string with whitespaces, or None.
  +                        if field_data and not field_data.isspace():
  +                            if '\n' in field_data and field == "license":
  +                                field_data = field_data.split('\n')[0]
   
  -                        embed.add_field(
  -                            name=field.replace("_", " ").title(),
  -                            value=escape_markdown(field_data),
  -                            inline=False,
  -                        )
  +                            embed.add_field(
  +                                name=field.replace("_", " ").title(),
  +                                value=escape_markdown(field_data),
  +                                inline=False,
  +                            )
   
  -            else:
  -                embed.description = "There was an error when fetching your PyPi package."
  -                log.trace(f"Error when fetching PyPi package: {response.status}.")
  +                    error = False
   
  -        await ctx.send(embed=embed)
  +                else:
  +                    embed.description = "There was an error when fetching your PyPi package."
  +                    log.trace(f"Error when fetching PyPi package: {response.status}.")
  +
  +        if error:
  +            await ctx.send(embed=embed, delete_after=INVALID_INPUT_DELETE_DELAY)
  +            await ctx.message.delete(delay=INVALID_INPUT_DELETE_DELAY)
  +        else:
  +            await ctx.send(embed=embed)
   
   
   def setup(bot: Bot) -> None:
  
verification_info: {"golden_diff": "diff --git a/bot/exts/info/pypi.py b/bot/exts/info/pypi.py\n--- a/bot/exts/info/pypi.py\n+++ b/bot/exts/info/pypi.py\n@@ -8,7 +8,7 @@\n from discord.utils import escape_markdown\n \n from bot.bot import Bot\n-from bot.constants import Colours, NEGATIVE_REPLIES\n+from bot.constants import Colours, NEGATIVE_REPLIES, RedirectOutput\n \n URL = \"https://pypi.org/pypi/{package}/json\"\n FIELDS = (\"author\", \"requires_python\", \"summary\", \"license\")\n@@ -17,6 +17,7 @@\n PYPI_COLOURS = itertools.cycle((Colours.yellow, Colours.blue, Colours.white))\n \n ILLEGAL_CHARACTERS = re.compile(r\"[^a-zA-Z0-9-.]+\")\n+INVALID_INPUT_DELETE_DELAY = RedirectOutput.delete_delay\n \n log = logging.getLogger(__name__)\n \n@@ -36,42 +37,49 @@\n         )\n         embed.set_thumbnail(url=PYPI_ICON)\n \n+        error = True\n+\n         if (character := re.search(ILLEGAL_CHARACTERS, package)) is not None:\n             embed.description = f\"Illegal character passed into command: '{escape_markdown(character.group(0))}'\"\n-            await ctx.send(embed=embed)\n-            return\n \n-        async with self.bot.http_session.get(URL.format(package=package)) as response:\n-            if response.status == 404:\n-                embed.description = \"Package could not be found.\"\n+        else:\n+            async with self.bot.http_session.get(URL.format(package=package)) as response:\n+                if response.status == 404:\n+                    embed.description = \"Package could not be found.\"\n \n-            elif response.status == 200 and response.content_type == \"application/json\":\n-                response_json = await response.json()\n-                info = response_json[\"info\"]\n+                elif response.status == 200 and response.content_type == \"application/json\":\n+                    response_json = await response.json()\n+                    info = response_json[\"info\"]\n \n-                embed.title = f\"{info['name']} v{info['version']}\"\n-                embed.url = info['package_url']\n-                embed.colour = next(PYPI_COLOURS)\n+                    embed.title = f\"{info['name']} v{info['version']}\"\n+                    embed.url = info['package_url']\n+                    embed.colour = next(PYPI_COLOURS)\n \n-                for field in FIELDS:\n-                    field_data = info[field]\n+                    for field in FIELDS:\n+                        field_data = info[field]\n \n-                    # Field could be completely empty, in some cases can be a string with whitespaces, or None.\n-                    if field_data and not field_data.isspace():\n-                        if '\\n' in field_data and field == \"license\":\n-                            field_data = field_data.split('\\n')[0]\n+                        # Field could be completely empty, in some cases can be a string with whitespaces, or None.\n+                        if field_data and not field_data.isspace():\n+                            if '\\n' in field_data and field == \"license\":\n+                                field_data = field_data.split('\\n')[0]\n \n-                        embed.add_field(\n-                            name=field.replace(\"_\", \" \").title(),\n-                            value=escape_markdown(field_data),\n-                            inline=False,\n-                        )\n+                            embed.add_field(\n+                                name=field.replace(\"_\", \" \").title(),\n+                                value=escape_markdown(field_data),\n+                                inline=False,\n+                            )\n \n-            else:\n-                embed.description = \"There was an error when fetching your PyPi package.\"\n-                log.trace(f\"Error when fetching PyPi package: {response.status}.\")\n+                    error = False\n \n-        await ctx.send(embed=embed)\n+                else:\n+                    embed.description = \"There was an error when fetching your PyPi package.\"\n+                    log.trace(f\"Error when fetching PyPi package: {response.status}.\")\n+\n+        if error:\n+            await ctx.send(embed=embed, delete_after=INVALID_INPUT_DELETE_DELAY)\n+            await ctx.message.delete(delay=INVALID_INPUT_DELETE_DELAY)\n+        else:\n+            await ctx.send(embed=embed)\n \n \n def setup(bot: Bot) -> None:\n", "issue": "Delete messages when `!pypi` module is invalid\nWhen users use the `!pypi` command with an invalid module, you currently get a response saying `\"Package could not be found.\"`. \r\n\r\nWhat I'm proposing it that after a delay (I believe we have `bot.constants.RedirectOutput.delete_delay` for this) the bot should delete both its response and the invocation message, like [`!d` currently does](https://github.com/python-discord/bot/blob/master/bot/exts/info/doc.py#L363-L365).\r\n\r\nThis would help reduce channel flooding when someone is trying to remember the name of a module, and since it's not a trivial change I'm happy to try and implement this myself if it's something we decide we want.\n", "before_files": [{"content": "import itertools\nimport logging\nimport random\nimport re\n\nfrom discord import Embed\nfrom discord.ext.commands import Cog, Context, command\nfrom discord.utils import escape_markdown\n\nfrom bot.bot import Bot\nfrom bot.constants import Colours, NEGATIVE_REPLIES\n\nURL = \"https://pypi.org/pypi/{package}/json\"\nFIELDS = (\"author\", \"requires_python\", \"summary\", \"license\")\nPYPI_ICON = \"https://cdn.discordapp.com/emojis/766274397257334814.png\"\n\nPYPI_COLOURS = itertools.cycle((Colours.yellow, Colours.blue, Colours.white))\n\nILLEGAL_CHARACTERS = re.compile(r\"[^a-zA-Z0-9-.]+\")\n\nlog = logging.getLogger(__name__)\n\n\nclass PyPi(Cog):\n    \"\"\"Cog for getting information about PyPi packages.\"\"\"\n\n    def __init__(self, bot: Bot):\n        self.bot = bot\n\n    @command(name=\"pypi\", aliases=(\"package\", \"pack\"))\n    async def get_package_info(self, ctx: Context, package: str) -> None:\n        \"\"\"Provide information about a specific package from PyPI.\"\"\"\n        embed = Embed(\n            title=random.choice(NEGATIVE_REPLIES),\n            colour=Colours.soft_red\n        )\n        embed.set_thumbnail(url=PYPI_ICON)\n\n        if (character := re.search(ILLEGAL_CHARACTERS, package)) is not None:\n            embed.description = f\"Illegal character passed into command: '{escape_markdown(character.group(0))}'\"\n            await ctx.send(embed=embed)\n            return\n\n        async with self.bot.http_session.get(URL.format(package=package)) as response:\n            if response.status == 404:\n                embed.description = \"Package could not be found.\"\n\n            elif response.status == 200 and response.content_type == \"application/json\":\n                response_json = await response.json()\n                info = response_json[\"info\"]\n\n                embed.title = f\"{info['name']} v{info['version']}\"\n                embed.url = info['package_url']\n                embed.colour = next(PYPI_COLOURS)\n\n                for field in FIELDS:\n                    field_data = info[field]\n\n                    # Field could be completely empty, in some cases can be a string with whitespaces, or None.\n                    if field_data and not field_data.isspace():\n                        if '\\n' in field_data and field == \"license\":\n                            field_data = field_data.split('\\n')[0]\n\n                        embed.add_field(\n                            name=field.replace(\"_\", \" \").title(),\n                            value=escape_markdown(field_data),\n                            inline=False,\n                        )\n\n            else:\n                embed.description = \"There was an error when fetching your PyPi package.\"\n                log.trace(f\"Error when fetching PyPi package: {response.status}.\")\n\n        await ctx.send(embed=embed)\n\n\ndef setup(bot: Bot) -> None:\n    \"\"\"Load the PyPi cog.\"\"\"\n    bot.add_cog(PyPi(bot))\n", "path": "bot/exts/info/pypi.py"}]}