Skip to content

Instantly share code, notes, and snippets.

@http-nova
Forked from AbstractUmbra/00-deprecation.md
Created February 19, 2024 18:08
Show Gist options
  • Select an option

  • Save http-nova/0048382e705783dff46fc6c28d6e1b4f to your computer and use it in GitHub Desktop.

Select an option

Save http-nova/0048382e705783dff46fc6c28d6e1b4f to your computer and use it in GitHub Desktop.
discord.py 2.0+ slash command info and examples
import discord
from discord import app_commands
from discord.ext import commands
class MyCog(commands.Cog):
def __init__(self, bot: commands.Bot) -> None:
self.bot = bot
group = app_commands.Group(name="parent", description="...")
# Above, we declare a command Group, in discord terms this is a parent command
# We define it within the class scope (not an instance scope) so we can use it as a decorator.
# This does have namespace caveats but i don't believe they're worth outlining in our needs.
@app_commands.command(name="top-command")
async def my_top_command(self, interaction: discord.Interaction) -> None:
""" /top-command """
await interaction.response.send_message("Hello from top level command!", ephemeral=True)
@group.command(name="sub-command") # we use the declared group to make a command.
async def my_sub_command(self, interaction: discord.Interaction) -> None:
""" /parent sub-command """
await interaction.response.send_message("Hello from the sub command!", ephemeral=True)
async def setup(bot: commands.Bot) -> None:
await bot.add_cog(MyCog(bot))
import discord
from discord import app_commands
from discord.ext import commands
class MyCog(commands.Cog):
def __init__(self, bot: commands.Bot) -> None:
self.bot = bot
@app_commands.command(name="command-1")
async def my_command(self, interaction: discord.Interaction) -> None:
""" /command-1 """
await interaction.response.send_message("Hello from command 1!", ephemeral=True)
@app_commands.command(name="command-2")
@app_commands.guilds(discord.Object(id=...), ...)
async def my_private_command(self, interaction: discord.Interaction) -> None:
""" /command-2 """
await interaction.response.send_message("Hello from private command!", ephemeral=True)
async def setup(bot: commands.Bot) -> None:
await bot.add_cog(MyCog(bot))
# for simplicity, these commands are all global. You can add `guild=` or `guilds=` to `Bot.add_cog` in `setup` to add them to a guild.
import discord
from discord import app_commands
from discord.ext import commands
class MyCog(commands.Cog, app_commands.Group, name="parent"):
def __init__(self, bot: commands.Bot) -> None:
self.bot = bot
super().__init__() # this is now required in this context.
@app_commands.command(name="sub-1")
async def my_sub_command_1(self, interaction: discord.Interaction) -> None:
""" /parent sub-1 """
await interaction.response.send_message("Hello from sub command 1", ephemeral=True)
@app_commands.command(name="sub-2")
async def my_sub_command_2(self, interaction: discord.Interaction) -> None:
""" /parent sub-2 """
await interaction.response.send_message("Hello from sub command 2", ephemeral=True)
async def setup(bot: commands.Bot) -> None:
await bot.add_cog(MyCog(bot))
# or if you want guild/guilds only...
await bot.add_cog(MyCog(bot), guilds=[discord.Object(id=...)])
import asyncio
from discord.ext import commands
from discord import app_commands
# define Bot with **needed** parameters
bot = commands.Bot(command_prefix="some_prefix", intents=some_intents_definition)
# You can now use `@bot.tree.command()` as a decorator:
@bot.tree.command()
async def my_command(interaction: discord.Interaction) -> None:
await interaction.response.send_message("Hello from my command!")
### NOTE: the above is a global command, see the `main()` func below:
# we can even use Groups
group = app_commands.Group(name="some-parent", description="description")
@group.command()
async def my_subcommand(interaction: discord.Interaction) -> None:
await interaction.response.send_message("hello from the subcommand!")
bot.tree.add_command(group, guild=discord.Object(id=...))
async def main():
async with bot:
# do you setup stuff if you need it here, then:
bot.tree.copy_global_to(guild=discord.Object(id=...)) # we copy the global commands we have to a guild, this is optional
await bot.start(MY_TOKEN)
# We still need to sync this tree somehow, but you can make a command as discussed already.

Slash Commands and you

This short example will cover how to make slash commands within an ext.commands.Bot's extension and Cog ecosystem.

There will be 3 examples:

  • A Cog Group, which will house all sub-commmands and the Cog is the parent.

    • This means the Cog class is regarded as the parent command, and all commands defined are "sub" commands. e.g. /cog sub_cmd
  • A free Cog, where all commands will be top-level.

    • This means like: i.e /my_cmd
  • A hybrid of the two, for when you want to group them accordingly.

    • So this will allow: i.e /parent sub_1, /parent sub_2 and /hello

I added how this command would be invoked in the doc strings.

This does not account for the fact you still need to sync Bot.tree somewhere, please remember to do this.

N.B: Ping Umbra#0009 in the d.py server if you want to suggest edits/improvements.

Sync examples and details

What I've been recommending to people, is to maintain a sync command as a Message Command (@bot.command()) or some sort of message invoke. Bots without the message content intent can still receive full dms or message content with a their mention in them.

It's not like you can use a slash command to sync... when that command isn't synced.

Syncing gotchas

There is a ratelimit on syncing global commands which add commands. Updating commands (currently) has no ratelimit.

It is still recommended to sync your commands to a test guild before syncing them globally. Discord.py has added a helper method to do just that: CommandTree.copy_global_to

This util is used as follows:

# you have a defined Bot, with a tree and have commands added to it that are global.

guild = ctx.guild or discord.Object(id=...)  # you can use a full discord.Guild as the method accepts a Snowflake
Bot.tree.copy_global_to(guild=guild)

All this method does is copy your defined global commands (so ones without a guild or guilds kwarg, or without the @app_commands.guilds() decorator) to the specified guild within the CommandTree. When you use this method you must sync afterward still, you can refer to when_to_sync.md for details there.

Syncing your commands

At the time of writing this, it's still mostly unclear to most users when they should be syncing their commands to Discord.

Let's try and write up some bullet points:-

When to sync

  • When you add a new command.
  • When a command's name or description changes.
  • When the callback's parameters change.
    • This includes parameter names, types or descriptions.
    • Also when you add or remove a parameter.
  • If you change a global to a guild command, or vice versa.
    • NOTE: If you do this, you will need to sync both global and to that guild to reflect the change.

These are currently the only times you should re-sync.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment