Search code examples
pythondiscord.pycommand

Discord.py - Check if Slash Command exists


I need help with checking if a Slash Command exists or not. My goal is it to add a slash command which lets you disable other slash commands. Therefore I need to check if the Command exists. This is the Code I have as of now:

@tree.command(guild = discord.Object(id=1129737425653071992), name='disable', description='Disable a specified Command')
async def disable(interaction: discord.Interaction, command: str):
    print(tree.get_commands(guild=discord.Object(id=1129737425653071992)))
    if command in tree.get_commands(guild=discord.Object(id=1129737425653071992)):
        await tree.remove_command(command)
        await interaction.response.send_message(f"{command} was disabled. You can reenable it by running /enable {command}")
    else:
        await interaction.response.send_message(f"Command could not be found: {command}")

When the command does not exist is does say so. But when it does it still says it does not exist.

I tried as you see in the code above what

tree.get_commands(guild=discord.Object(id=1129737425653071992)

prints, which is just something like this: <discord.app_commands.commands.Command object at 0x000002A6994B22D0>

How can I make a working check if a slash command exists?


Solution

  • Small thing first, tree.remove_command(command) is not async.

    Anyways, what you're really trying to do is disable the commands anyway so,

    How to create a disable command in discord.py

    Check for if it exists

    tree.get_commands returns:

    List[Union[ContextMenu, Command, Group]]
    

    This means that you'll have to parse it if you want to check the Command specifically. The command parameter is also a string which is why it didn't return true in the first place. However, there's an easier command we can use in the command tree.

    What to do instead

    tree.get_command (singular not plural) returns:

    Optional[Union[Command, ContextMenu, Group]]
    

    Yes, it is the same thing. However, the parameters are different.

    command (str) – The name of the root command to get.

    guild (Optional[Snowflake]) – The guild to get the command from. If not given or None then it gets a global command instead.

    type (AppCommandType) – The type of command to get. Defaults to chat_input, i.e. slash commands.

    You can pass in the command string parameter from before into this command. Then you can check if it returned anything at all. This is way faster than parsing (as mentioned before). You're also not checking for if multiple commands exist, so this is the best option.

    Below I have a code example (for reference I made another command earlier):

    @tree.command(guild=discord.Object(id=guild_id), name='disable', description='Disable a specified Command')
    async def disable(interaction: discord.Interaction, command: str):
        if tree.get_command(command, guild=discord.Object(id=guild_id)):
            tree.remove_command(command, guild=discord.Object(id=guild_id))  # remove the command
            await interaction.response.send_message(
                f"{command} was disabled. You can reenable it by running /enable {command}")
        else:
            await interaction.response.send_message(f"Command could not be found: {command}")
    

    Image of it working

    Disabling the command

    However, this doesn't actually disable the command. Why is this? Well, tree.remove_command requires the tree to be synced. Simply add the line:

    await tree.sync(guild=discord.Object(id=guild_id))
    

    and it should work!

    Full code:

    @tree.command(guild=discord.Object(id=guild_id), name='disable', description='Disable a specified Command')
    async def disable(interaction: discord.Interaction, command: str):
        await interaction.response.defer()
        if tree.get_command(command, guild=discord.Object(id=guild_id)):  # check if the command exists
            tree.remove_command(command, guild=discord.Object(id=guild_id))  # remove the command
            print("command removed!")
            await tree.sync(guild=discord.Object(id=guild_id))  # sync the tree
            print("tree synced!")
            await interaction.followup.send(
                f"{command} was disabled. You can reenable it by running /enable {command}")
        else:
            await interaction.followup.send(f"Command could not be found: {command}")
    

    Tested this locally & the slash command say doesn't appear anymore. It's also gone from integrations: say command is gone