prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  Logic in Source Command's Help Command Check
  ## Description
  <!-- Describe the bug you've found -->
  Its impossible to get the source for the HelpChannel cog.
  
  ## Steps to Reproduce
  <!-- Detail the exact list of steps to be able to encounter the bug -->
  `!src HelpChannel`
  Due to the logic of the command, all that needs to be said is `!src help` followed by anything.
  
  ## Expected Behaviour
  <!-- Outline what you expect to occur, include screenshots if relevant -->
  Source link to the HelpChannel cog is shown.
  
  ## Actual Behaviour
  <!-- Outline what occurs instead of the expected behavior, include screenshots if relevant -->
  Help command source link is shown.
  
  ## Known Impacted Platforms
  <!-- Replace [ ] with [x] to mark items -->
  
  - [x] Web
  - [x] Desktop
  - [x] Android App
  - [x] iOS App
  
  ## Possible Solutions
  <!-- Detail any solutions you might have in mind to be able to resolve the bug -->
  These lines are the probable cause.
  https://github.com/python-discord/bot/blob/51af1369e0d9c2ad185f0c0920b599b7187ed077/bot/exts/info/source.py#L19-L20
  After looking at sir-lancebot, it might even be possible to remove these two lines altogether.
  ## Would you like to implement a fix?
  
  ***Note: For high-priority or critical bugs, fixes may be implemented by staff.***
  <!-- Replace [ ] with [x] with your choice -->
  
  - [ ] I'd like to implement the bug fix
  - [x] Anyone can implement the bug fix
  
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `bot/exts/info/source.py`
  Content:
  ```
  1 import inspect
  2 from pathlib import Path
  3 from typing import Optional, Tuple, Union
  4 
  5 from discord import Embed, utils
  6 from discord.ext import commands
  7 
  8 from bot.bot import Bot
  9 from bot.constants import URLs
  10 
  11 SourceType = Union[commands.HelpCommand, commands.Command, commands.Cog, str, commands.ExtensionNotLoaded]
  12 
  13 
  14 class SourceConverter(commands.Converter):
  15     """Convert an argument into a help command, tag, command, or cog."""
  16 
  17     async def convert(self, ctx: commands.Context, argument: str) -> SourceType:
  18         """Convert argument into source object."""
  19         if argument.lower().startswith("help"):
  20             return ctx.bot.help_command
  21 
  22         cog = ctx.bot.get_cog(argument)
  23         if cog:
  24             return cog
  25 
  26         cmd = ctx.bot.get_command(argument)
  27         if cmd:
  28             return cmd
  29 
  30         tags_cog = ctx.bot.get_cog("Tags")
  31         show_tag = True
  32 
  33         if not tags_cog:
  34             show_tag = False
  35         elif argument.lower() in tags_cog._cache:
  36             return argument.lower()
  37 
  38         escaped_arg = utils.escape_markdown(argument)
  39 
  40         raise commands.BadArgument(
  41             f"Unable to convert '{escaped_arg}' to valid command{', tag,' if show_tag else ''} or Cog."
  42         )
  43 
  44 
  45 class BotSource(commands.Cog):
  46     """Displays information about the bot's source code."""
  47 
  48     def __init__(self, bot: Bot):
  49         self.bot = bot
  50 
  51     @commands.command(name="source", aliases=("src",))
  52     async def source_command(self, ctx: commands.Context, *, source_item: SourceConverter = None) -> None:
  53         """Display information and a GitHub link to the source code of a command, tag, or cog."""
  54         if not source_item:
  55             embed = Embed(title="Bot's GitHub Repository")
  56             embed.add_field(name="Repository", value=f"[Go to GitHub]({URLs.github_bot_repo})")
  57             embed.set_thumbnail(url="https://avatars1.githubusercontent.com/u/9919")
  58             await ctx.send(embed=embed)
  59             return
  60 
  61         embed = await self.build_embed(source_item)
  62         await ctx.send(embed=embed)
  63 
  64     def get_source_link(self, source_item: SourceType) -> Tuple[str, str, Optional[int]]:
  65         """
  66         Build GitHub link of source item, return this link, file location and first line number.
  67 
  68         Raise BadArgument if `source_item` is a dynamically-created object (e.g. via internal eval).
  69         """
  70         if isinstance(source_item, commands.Command):
  71             source_item = inspect.unwrap(source_item.callback)
  72             src = source_item.__code__
  73             filename = src.co_filename
  74         elif isinstance(source_item, str):
  75             tags_cog = self.bot.get_cog("Tags")
  76             filename = tags_cog._cache[source_item]["location"]
  77         else:
  78             src = type(source_item)
  79             try:
  80                 filename = inspect.getsourcefile(src)
  81             except TypeError:
  82                 raise commands.BadArgument("Cannot get source for a dynamically-created object.")
  83 
  84         if not isinstance(source_item, str):
  85             try:
  86                 lines, first_line_no = inspect.getsourcelines(src)
  87             except OSError:
  88                 raise commands.BadArgument("Cannot get source for a dynamically-created object.")
  89 
  90             lines_extension = f"#L{first_line_no}-L{first_line_no+len(lines)-1}"
  91         else:
  92             first_line_no = None
  93             lines_extension = ""
  94 
  95         # Handle tag file location differently than others to avoid errors in some cases
  96         if not first_line_no:
  97             file_location = Path(filename).relative_to("/bot/")
  98         else:
  99             file_location = Path(filename).relative_to(Path.cwd()).as_posix()
  100 
  101         url = f"{URLs.github_bot_repo}/blob/main/{file_location}{lines_extension}"
  102 
  103         return url, file_location, first_line_no or None
  104 
  105     async def build_embed(self, source_object: SourceType) -> Optional[Embed]:
  106         """Build embed based on source object."""
  107         url, location, first_line = self.get_source_link(source_object)
  108 
  109         if isinstance(source_object, commands.HelpCommand):
  110             title = "Help Command"
  111             description = source_object.__doc__.splitlines()[1]
  112         elif isinstance(source_object, commands.Command):
  113             description = source_object.short_doc
  114             title = f"Command: {source_object.qualified_name}"
  115         elif isinstance(source_object, str):
  116             title = f"Tag: {source_object}"
  117             description = ""
  118         else:
  119             title = f"Cog: {source_object.qualified_name}"
  120             description = source_object.description.splitlines()[0]
  121 
  122         embed = Embed(title=title, description=description)
  123         embed.add_field(name="Source Code", value=f"[Go to GitHub]({url})")
  124         line_text = f":{first_line}" if first_line else ""
  125         embed.set_footer(text=f"{location}{line_text}")
  126 
  127         return embed
  128 
  129 
  130 def setup(bot: Bot) -> None:
  131     """Load the BotSource cog."""
  132     bot.add_cog(BotSource(bot))
  133
  ```
  --- 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/bot/exts/info/source.py b/bot/exts/info/source.py
  --- a/bot/exts/info/source.py
  +++ b/bot/exts/info/source.py
  @@ -14,9 +14,10 @@
   class SourceConverter(commands.Converter):
       """Convert an argument into a help command, tag, command, or cog."""
   
  -    async def convert(self, ctx: commands.Context, argument: str) -> SourceType:
  +    @staticmethod
  +    async def convert(ctx: commands.Context, argument: str) -> SourceType:
           """Convert argument into source object."""
  -        if argument.lower().startswith("help"):
  +        if argument.lower() == "help":
               return ctx.bot.help_command
   
           cog = ctx.bot.get_cog(argument)
  
verification_info: {"golden_diff": "diff --git a/bot/exts/info/source.py b/bot/exts/info/source.py\n--- a/bot/exts/info/source.py\n+++ b/bot/exts/info/source.py\n@@ -14,9 +14,10 @@\n class SourceConverter(commands.Converter):\n     \"\"\"Convert an argument into a help command, tag, command, or cog.\"\"\"\n \n-    async def convert(self, ctx: commands.Context, argument: str) -> SourceType:\n+    @staticmethod\n+    async def convert(ctx: commands.Context, argument: str) -> SourceType:\n         \"\"\"Convert argument into source object.\"\"\"\n-        if argument.lower().startswith(\"help\"):\n+        if argument.lower() == \"help\":\n             return ctx.bot.help_command\n \n         cog = ctx.bot.get_cog(argument)\n", "issue": "Logic in Source Command's Help Command Check\n## Description\r\n<!-- Describe the bug you've found -->\r\nIts impossible to get the source for the HelpChannel cog.\r\n\r\n## Steps to Reproduce\r\n<!-- Detail the exact list of steps to be able to encounter the bug -->\r\n`!src HelpChannel`\r\nDue to the logic of the command, all that needs to be said is `!src help` followed by anything.\r\n\r\n## Expected Behaviour\r\n<!-- Outline what you expect to occur, include screenshots if relevant -->\r\nSource link to the HelpChannel cog is shown.\r\n\r\n## Actual Behaviour\r\n<!-- Outline what occurs instead of the expected behavior, include screenshots if relevant -->\r\nHelp command source link is shown.\r\n\r\n## Known Impacted Platforms\r\n<!-- Replace [ ] with [x] to mark items -->\r\n\r\n- [x] Web\r\n- [x] Desktop\r\n- [x] Android App\r\n- [x] iOS App\r\n\r\n## Possible Solutions\r\n<!-- Detail any solutions you might have in mind to be able to resolve the bug -->\r\nThese lines are the probable cause.\r\nhttps://github.com/python-discord/bot/blob/51af1369e0d9c2ad185f0c0920b599b7187ed077/bot/exts/info/source.py#L19-L20\r\nAfter looking at sir-lancebot, it might even be possible to remove these two lines altogether.\r\n## Would you like to implement a fix?\r\n\r\n***Note: For high-priority or critical bugs, fixes may be implemented by staff.***\r\n<!-- Replace [ ] with [x] with your choice -->\r\n\r\n- [ ] I'd like to implement the bug fix\r\n- [x] Anyone can implement the bug fix\r\n\n", "before_files": [{"content": "import inspect\nfrom pathlib import Path\nfrom typing import Optional, Tuple, Union\n\nfrom discord import Embed, utils\nfrom discord.ext import commands\n\nfrom bot.bot import Bot\nfrom bot.constants import URLs\n\nSourceType = Union[commands.HelpCommand, commands.Command, commands.Cog, str, commands.ExtensionNotLoaded]\n\n\nclass SourceConverter(commands.Converter):\n    \"\"\"Convert an argument into a help command, tag, command, or cog.\"\"\"\n\n    async def convert(self, ctx: commands.Context, argument: str) -> SourceType:\n        \"\"\"Convert argument into source object.\"\"\"\n        if argument.lower().startswith(\"help\"):\n            return ctx.bot.help_command\n\n        cog = ctx.bot.get_cog(argument)\n        if cog:\n            return cog\n\n        cmd = ctx.bot.get_command(argument)\n        if cmd:\n            return cmd\n\n        tags_cog = ctx.bot.get_cog(\"Tags\")\n        show_tag = True\n\n        if not tags_cog:\n            show_tag = False\n        elif argument.lower() in tags_cog._cache:\n            return argument.lower()\n\n        escaped_arg = utils.escape_markdown(argument)\n\n        raise commands.BadArgument(\n            f\"Unable to convert '{escaped_arg}' to valid command{', tag,' if show_tag else ''} or Cog.\"\n        )\n\n\nclass BotSource(commands.Cog):\n    \"\"\"Displays information about the bot's source code.\"\"\"\n\n    def __init__(self, bot: Bot):\n        self.bot = bot\n\n    @commands.command(name=\"source\", aliases=(\"src\",))\n    async def source_command(self, ctx: commands.Context, *, source_item: SourceConverter = None) -> None:\n        \"\"\"Display information and a GitHub link to the source code of a command, tag, or cog.\"\"\"\n        if not source_item:\n            embed = Embed(title=\"Bot's GitHub Repository\")\n            embed.add_field(name=\"Repository\", value=f\"[Go to GitHub]({URLs.github_bot_repo})\")\n            embed.set_thumbnail(url=\"https://avatars1.githubusercontent.com/u/9919\")\n            await ctx.send(embed=embed)\n            return\n\n        embed = await self.build_embed(source_item)\n        await ctx.send(embed=embed)\n\n    def get_source_link(self, source_item: SourceType) -> Tuple[str, str, Optional[int]]:\n        \"\"\"\n        Build GitHub link of source item, return this link, file location and first line number.\n\n        Raise BadArgument if `source_item` is a dynamically-created object (e.g. via internal eval).\n        \"\"\"\n        if isinstance(source_item, commands.Command):\n            source_item = inspect.unwrap(source_item.callback)\n            src = source_item.__code__\n            filename = src.co_filename\n        elif isinstance(source_item, str):\n            tags_cog = self.bot.get_cog(\"Tags\")\n            filename = tags_cog._cache[source_item][\"location\"]\n        else:\n            src = type(source_item)\n            try:\n                filename = inspect.getsourcefile(src)\n            except TypeError:\n                raise commands.BadArgument(\"Cannot get source for a dynamically-created object.\")\n\n        if not isinstance(source_item, str):\n            try:\n                lines, first_line_no = inspect.getsourcelines(src)\n            except OSError:\n                raise commands.BadArgument(\"Cannot get source for a dynamically-created object.\")\n\n            lines_extension = f\"#L{first_line_no}-L{first_line_no+len(lines)-1}\"\n        else:\n            first_line_no = None\n            lines_extension = \"\"\n\n        # Handle tag file location differently than others to avoid errors in some cases\n        if not first_line_no:\n            file_location = Path(filename).relative_to(\"/bot/\")\n        else:\n            file_location = Path(filename).relative_to(Path.cwd()).as_posix()\n\n        url = f\"{URLs.github_bot_repo}/blob/main/{file_location}{lines_extension}\"\n\n        return url, file_location, first_line_no or None\n\n    async def build_embed(self, source_object: SourceType) -> Optional[Embed]:\n        \"\"\"Build embed based on source object.\"\"\"\n        url, location, first_line = self.get_source_link(source_object)\n\n        if isinstance(source_object, commands.HelpCommand):\n            title = \"Help Command\"\n            description = source_object.__doc__.splitlines()[1]\n        elif isinstance(source_object, commands.Command):\n            description = source_object.short_doc\n            title = f\"Command: {source_object.qualified_name}\"\n        elif isinstance(source_object, str):\n            title = f\"Tag: {source_object}\"\n            description = \"\"\n        else:\n            title = f\"Cog: {source_object.qualified_name}\"\n            description = source_object.description.splitlines()[0]\n\n        embed = Embed(title=title, description=description)\n        embed.add_field(name=\"Source Code\", value=f\"[Go to GitHub]({url})\")\n        line_text = f\":{first_line}\" if first_line else \"\"\n        embed.set_footer(text=f\"{location}{line_text}\")\n\n        return embed\n\n\ndef setup(bot: Bot) -> None:\n    \"\"\"Load the BotSource cog.\"\"\"\n    bot.add_cog(BotSource(bot))\n", "path": "bot/exts/info/source.py"}], "after_files": [{"content": "import inspect\nfrom pathlib import Path\nfrom typing import Optional, Tuple, Union\n\nfrom discord import Embed, utils\nfrom discord.ext import commands\n\nfrom bot.bot import Bot\nfrom bot.constants import URLs\n\nSourceType = Union[commands.HelpCommand, commands.Command, commands.Cog, str, commands.ExtensionNotLoaded]\n\n\nclass SourceConverter(commands.Converter):\n    \"\"\"Convert an argument into a help command, tag, command, or cog.\"\"\"\n\n    @staticmethod\n    async def convert(ctx: commands.Context, argument: str) -> SourceType:\n        \"\"\"Convert argument into source object.\"\"\"\n        if argument.lower() == \"help\":\n            return ctx.bot.help_command\n\n        cog = ctx.bot.get_cog(argument)\n        if cog:\n            return cog\n\n        cmd = ctx.bot.get_command(argument)\n        if cmd:\n            return cmd\n\n        tags_cog = ctx.bot.get_cog(\"Tags\")\n        show_tag = True\n\n        if not tags_cog:\n            show_tag = False\n        elif argument.lower() in tags_cog._cache:\n            return argument.lower()\n\n        escaped_arg = utils.escape_markdown(argument)\n\n        raise commands.BadArgument(\n            f\"Unable to convert '{escaped_arg}' to valid command{', tag,' if show_tag else ''} or Cog.\"\n        )\n\n\nclass BotSource(commands.Cog):\n    \"\"\"Displays information about the bot's source code.\"\"\"\n\n    def __init__(self, bot: Bot):\n        self.bot = bot\n\n    @commands.command(name=\"source\", aliases=(\"src\",))\n    async def source_command(self, ctx: commands.Context, *, source_item: SourceConverter = None) -> None:\n        \"\"\"Display information and a GitHub link to the source code of a command, tag, or cog.\"\"\"\n        if not source_item:\n            embed = Embed(title=\"Bot's GitHub Repository\")\n            embed.add_field(name=\"Repository\", value=f\"[Go to GitHub]({URLs.github_bot_repo})\")\n            embed.set_thumbnail(url=\"https://avatars1.githubusercontent.com/u/9919\")\n            await ctx.send(embed=embed)\n            return\n\n        embed = await self.build_embed(source_item)\n        await ctx.send(embed=embed)\n\n    def get_source_link(self, source_item: SourceType) -> Tuple[str, str, Optional[int]]:\n        \"\"\"\n        Build GitHub link of source item, return this link, file location and first line number.\n\n        Raise BadArgument if `source_item` is a dynamically-created object (e.g. via internal eval).\n        \"\"\"\n        if isinstance(source_item, commands.Command):\n            source_item = inspect.unwrap(source_item.callback)\n            src = source_item.__code__\n            filename = src.co_filename\n        elif isinstance(source_item, str):\n            tags_cog = self.bot.get_cog(\"Tags\")\n            filename = tags_cog._cache[source_item][\"location\"]\n        else:\n            src = type(source_item)\n            try:\n                filename = inspect.getsourcefile(src)\n            except TypeError:\n                raise commands.BadArgument(\"Cannot get source for a dynamically-created object.\")\n\n        if not isinstance(source_item, str):\n            try:\n                lines, first_line_no = inspect.getsourcelines(src)\n            except OSError:\n                raise commands.BadArgument(\"Cannot get source for a dynamically-created object.\")\n\n            lines_extension = f\"#L{first_line_no}-L{first_line_no+len(lines)-1}\"\n        else:\n            first_line_no = None\n            lines_extension = \"\"\n\n        # Handle tag file location differently than others to avoid errors in some cases\n        if not first_line_no:\n            file_location = Path(filename).relative_to(\"/bot/\")\n        else:\n            file_location = Path(filename).relative_to(Path.cwd()).as_posix()\n\n        url = f\"{URLs.github_bot_repo}/blob/main/{file_location}{lines_extension}\"\n\n        return url, file_location, first_line_no or None\n\n    async def build_embed(self, source_object: SourceType) -> Optional[Embed]:\n        \"\"\"Build embed based on source object.\"\"\"\n        url, location, first_line = self.get_source_link(source_object)\n\n        if isinstance(source_object, commands.HelpCommand):\n            title = \"Help Command\"\n            description = source_object.__doc__.splitlines()[1]\n        elif isinstance(source_object, commands.Command):\n            description = source_object.short_doc\n            title = f\"Command: {source_object.qualified_name}\"\n        elif isinstance(source_object, str):\n            title = f\"Tag: {source_object}\"\n            description = \"\"\n        else:\n            title = f\"Cog: {source_object.qualified_name}\"\n            description = source_object.description.splitlines()[0]\n\n        embed = Embed(title=title, description=description)\n        embed.add_field(name=\"Source Code\", value=f\"[Go to GitHub]({url})\")\n        line_text = f\":{first_line}\" if first_line else \"\"\n        embed.set_footer(text=f\"{location}{line_text}\")\n\n        return embed\n\n\ndef setup(bot: Bot) -> None:\n    \"\"\"Load the BotSource cog.\"\"\"\n    bot.add_cog(BotSource(bot))\n", "path": "bot/exts/info/source.py"}]}