Majd Thaher
Majd Thaher

Reputation: 47

add_command discord.py not working "The command passed must be a subclass of Command"

I am currently updating my discord bot and wanted to add new functionality which allows me to add and remove commands through discord, without having to modify the code directly.

I found out that there are already existing methods (namely "Bot.add_command" and "Bot.remove_command" which do exactly what I want.

The "remove_command" part works perfectly, but I'm having trouble adding back the command using the add_command function. I've read the documentation but I don't seem to understand what's causing my error (outlined below).

Code:

    @client.command()
    @commands.has_permissions(administrator = True)
    async def removecommand(ctx, command):
        try:
            client.remove_command(command)
        except Exception as err:
            print(err) 
        await ctx.message.add_reaction('✅')
    
    @client.command()
    @commands.has_permissions(administrator = True)
    async def addcommand(ctx, command):
        command = client.get_command(command)
        await client.add_command(command)
        await ctx.message.add_reaction('✅')

Error: discord.ext.commands.errors.CommandInvokeError: Command raised an exception: TypeError: The command passed must be a subclass of Command

Could someone please help me? I don't seem to understand what this means. Thank you.

Traceback (most recent call last):
  File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/discord/ext/commands/core.py", line 85, in wrapped
    ret = await coro(*args, **kwargs)
  File "/Users/name/Desktop/discord mj market/1 mainmarketplace.py", line 121, in addcommand
    await client.add_command(command)
  File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/discord/ext/commands/core.py", line 1132, in add_command
    raise TypeError('The command passed must be a subclass of Command')
TypeError: The command passed must be a subclass of Command

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/discord/ext/commands/bot.py", line 903, in invoke
    await ctx.command.invoke(ctx)
  File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/discord/ext/commands/core.py", line 859, in invoke
    await injected(*ctx.args, **ctx.kwargs)
  File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/discord/ext/commands/core.py", line 94, in wrapped
    raise CommandInvokeError(exc) from exc
discord.ext.commands.errors.CommandInvokeError: Command raised an exception: TypeError: The command passed must be a subclass of Command

Upvotes: 1

Views: 1100

Answers (2)

Ali Hakan Kurt
Ali Hakan Kurt

Reputation: 1037

discord.utils.find(lambda cmd: str(cmd) == "yourcmdname", client.commands)

This will find your bot's command if exists else returns None. Also if you will use that removed command again, you can disable it.

@client.command()
async def toggle(ctx, cmd):
    command = discord.utils.find(lambda c: str(c) == cmd, client.commands)
    if command:
        command.enabled = not command.enabled
        if command.enabled:
            await ctx.send(f"{cmd} enabled.")
        else:
            await ctx.send(f"{cmd} disabled.")
    else:
        await ctx.send("Command not found")

Upvotes: 3

Jacob Lee
Jacob Lee

Reputation: 4700

The argument command passed to add_command or remove_command must be a discord.ext.commands.Command object. When members of your guild call the command, they will be passing strings to the argument (hence the error message).

There are two ways to get the Command object corresponding to a command name:

  1. (Recommended) Using the Bot.get_command() method. This will return the Command object corresponding to a command name (or alias) or None, if the command cannot be found. Note: Command names are case-sensitive.
  2. Using the Bot.walk_commands() method. This will return a generator yielding each Command object connected to the Bot object.

As for the add_command() method, the argument must also be a Command object. Thus, you would have to create your own Command object (which requires a function func and a name name, among other things). It would be best to have the functions already defined as Command objects (using the Bot.command() decorator). If that is the case, then the above two methods will work as well.


Bot.get_command()

@client.command()
@commands.has_permissions(administrator = True)
async def removecommand(ctx, command):
    cmd = client.get_command(command)
    if cmd is None:
        await ctx.channel.send(f"Command `{command}` does not exist")
    client.remove_command(cmd)
    await ctx.message.add_reaction('✅')

Bot.walk_commands()

@client.command()
@commands.has_permissions(administrator = True)
async def removecommand(ctx, command):
    for cmd in client.walk_commands():
        if cmd.name.lower() == command.lower():
            client.remove_command(cmd)
            await ctx.message.add_reaction('✅')
            return
    await ctx.channel.send(f"Command `{command}` does not exist")

Upvotes: 1

Related Questions