... to my blog style space for easier contribution by third parties and to provide what I believe to be an easier reading experience. Please field all enquiries and issues to the source repository.
-
-
Save AbstractUmbra/a9c188797ae194e592efe05fa129c57f to your computer and use it in GitHub Desktop.
how to just invoke the parent command?
Can we have same example but without cogs? Please ^^'
(Sorry to clog up a gist with comments again buttt....)
On that note, could anyone direct me to any gists/docs regarding syncing the bot tree with slash commands in either cogs or the main bot script?
I'm having some trouble getting the slash commands to populate, and the bot's been running for a couple days now.
Relevant code:
It is a bit of a slog finding and compiling the useful documentation at this point. (Though I'm sure that'll get better when it comes closer to release.)
I'd also be happy to be considered for contributed documentation (it's something of a obsession specialty of mine), if only in a minor capacity
@glass-ships Can do!
So I am a HUGE advocate for having absolutely ZERO autosync.
This means that all syncing should be done manually, by you, as needed.
I've seen people do their sync in on_ready
, or setup_hook
and I hate it, to be honest.
You do NOT need to sync like this, since the ratelimit for this endpoint not lax and has a cap for daily usage when creating commands.
Updating them has a different ratelimit of which I am not familiar with.
Instead what I suggest is making a command to do this.
Now I can respect people wanna move to slash commmands fully and drop the message commands, that's okay. I still recommend some sort of manual trigger for syncing their CommandTree, like sommething listening in on_message
for specific instructions in a locked dev channel, etc.
I have an example command here:
Click to expand!
@bot.command()
@commands.guild_only()
@commands.is_owner()
async def sync(ctx: Context, guilds: Greedy[discord.Object], spec: Optional[Literal["~", "*", "^"]] = None) -> None:
if not guilds:
if spec == "~":
synced = await ctx.bot.tree.sync(guild=ctx.guild)
elif spec == "*":
ctx.bot.tree.copy_global_to(guild=ctx.guild)
synced = await ctx.bot.tree.sync(guild=ctx.guild)
elif spec == "^":
ctx.bot.tree.clear_commands(guild=ctx.guild)
await ctx.bot.tree.sync(guild=ctx.guild)
synced = []
else:
synced = await ctx.bot.tree.sync()
await ctx.send(
f"Synced {len(synced)} commands {'globally' if spec is None else 'to the current guild.'}"
)
return
ret = 0
for guild in guilds:
try:
await ctx.bot.tree.sync(guild=guild)
except discord.HTTPException:
pass
else:
ret += 1
await ctx.send(f"Synced the tree to {ret}/{len(guilds)}.")
commands.Greedy
discord.Object
typing.Optional
and typing.Literal
Works like:
!sync
-> global sync
!sync ~
-> sync current guild
!sync *
-> copies all global app commands to current guild and syncs
!sync ^
-> clears all commands from the current guild target and syncs (removes guild commands)
!sync id_1 id_2
-> syncs guilds with id 1 and 2
So general protocol for syncing is whilst your commands are still being worked on, you want to just sync them to a test guild only, not globally. This avoids the super mean global sync ratelimit.
Once the commmands are ready for deployment globally, you can sync globally.
Discord.py provided utilities such as ComandTree.copy_global_to
that can copy a globally defined application command to a guild logically, so you can have comands defined globally but during testing just copy it to a guild for syncing.
You can retrofit this tool into the example commmand if you need to!
how to just invoke the parent command?
This is currently not supported by Discord, lol.
In the first line of the function def:
async def sync(self, ctx: Context, guilds: Greedy[Object], spec: Optional[Literal["~"]] = None) -> None:
I'm assuming Context, Greedy, and Object are classes of discord
, are Optional
and Literal
also discord classes? Or were these imported from typing
?
This is amazing by the way, thank you so much! Implementing now to test it out and see how it works in action
Update:
The command returns that "2 commands were synced to the current guild", but after another day of waiting, both test slash commands are still not showing :/
Another update - I finally got slash commands populating in my test guild!!
The trick was that when you invite a bot to a guild, it has to be with both the bot
and applications.commands
scopes.
So your invite link should look like:
https://discord.com/oauth2/authorize?client_id=&scope=bot&permissions=8&scope=applications.commands
thank you for this.
The term hybrid is a new feature according to https://discordapp.com/channels/336642139381301249/381965829857738772/965731673717223495
that enables ext.commands to be re-used as slash commands.
You use the term hybrid but I don;t see you using @commands.hybrid_command() or @commands.hybrid_group()
Can't link the line for some reason but line 7 to 10 in extension_with_group-py should be changed to the following:
class MyCog(commands.GroupCog, group_name="parent"):
def __init__(self, bot: commands.Bot) -> None:
self.bot = bot
Agreed, done.
I have also updated to show an actual hybrid commands example.
thank you for this.
The term hybrid is a new feature according to https://discordapp.com/channels/336642139381301249/381965829857738772/965731673717223495 that enables ext.commands to be re-used as slash commands.
You use the term hybrid but I don;t see you using @commands.hybrid_command() or @commands.hybrid_group()
Delayed, but this has been done.
Can we have same example but without cogs? Please ^^'
https://github.com/Rapptz/discord.py/blob/master/examples/app_commands/basic.py
Can we have same example but without cogs? Please ^^'
https://github.com/Rapptz/discord.py/blob/master/examples/app_commands/basic.py
I also have this above.
How would I describe option in hybrid commands? With app_commands.describe
? Or some other way?
Thank you, this gist is very helpful
I fail to understand how the bot is run, I cant see anywhere a bot.run(token=...) nor how to use this async def setup mind enlighting me please ? :D
@Tyskiep99 These are Cogs, and are meant to be used with a separate python script for the "main" bot, which will "load" or "import" these cogs.
the bot.run and setup() methods are defined elsewhere, and don't affect the way these cogs are written.
Yes I noticed afterward, I had deleted that comment, sorry about that, I have seen the https://discordpy.readthedocs.io/en/stable/migrating.html#asyncio-event-loop-changes thanks for the reply !
I've got one more question, please, I have trouble with the Greedy param from @AbstractUmbra example of sync command, it seems it doenst work:
discord.ext.commands.errors.ExtensionFailed: Extension 'eqdkp_ng.cogs.admin' raised an error: TypeError: unhashable type: 'Greedy'
my import in the cog is as follow:
import discord
from discord.ext import commands
# and the params:
guilds: commands.Greedy[discord.Object]
It is an annotation, not an assignment.
You have =
, you should have :
sorry that was a typo, it is a :
I also tried with guilds: commands.Greedy[discord.Guild]
but same effect, I use it in a @app_commands.command()
in the cog maybe that is why? Is it only reserved to old bot.command
?
Yes, app commands have no capability of consumption arguments. The sync command presented is designed as a Message command only.
Thanks a lot for the information.
Altho I have another question sorry to bother but I cant any information anywhere about it,
I have an app command using my models from db to load items for a converter (event: Enum('Events', Event.get_event_dict_enum_from_db())
).
And I have another command to add new entry in the db. I dont use bot.tree.copy_global_to
(should I?) I also dont use bot.tree.sync
anywhere (yet).
The issue I am facing is when I add a new entry for the converter in the db, and after issuing the !sync
or !sync ~
command, the list is not updated. I tried to put a .sync
after the entry is added in the adding command but without success too.
How would you tackle this? Is it even possible? (the command converter list get updated after a reboot of the bot and a sync) - the bot is intended to be used only within one guild
This would be better discussed in the discord.py server as I'm not fully understanding what you're asking.
You do need to sync your slash commands, but read over this first.
Are we supposed to call setup
ourselves via asyncio
? It's not really clear. I'm coming from the old and easy on_message()
and I'm totally lost.
and how do you load em to use em??? i cant load em in any wise idk
Hello Umbra, want to suggest some changes for #file-9-subclassing_group-py...
- # this a app command group
+ # this is an App command group
- # you can nest these up 1:
- # `/group group` = VALID
+ # Valid combinations:
+ # /group subcommand (up to 25)
+ # /group subcommand group
+ # /group subcommand group subcommand (up to 25)
- # /group group group` = INVALID
- # etc... all invalid.
# this example shows one way to do this, subclassing
# the other is constructing an instance of app_commands.Group()
# that one is shown in "free_function_commands-py"
import discord
from discord import app_commands
- # the @app_commands.guilds and others (including checks) can be used above the class
+ # checks like @app_commands.guilds and @app_commands.default_permissions can be used above the class
- # these will apply to ALL subcommand, subcommands cannot have invidual perms!
+ # these will apply to all subcommands, subcommands cannot have individual perms.
@app_commands.guild_only()
class Group(app_commands.Group):
Hello Umbra, want to suggest some changes for #file-9-subclassing_group-py...
- # this a app command group + # this is an App command group - # you can nest these up 1: - # `/group group` = VALID + # Valid combinations: + # /group subcommand (up to 25) + # /group subcommand group + # /group subcommand group subcommand (up to 25) - # /group group group` = INVALID - # etc... all invalid. # this example shows one way to do this, subclassing # the other is constructing an instance of app_commands.Group() # that one is shown in "free_function_commands-py" import discord from discord import app_commands - # the @app_commands.guilds and others (including checks) can be used above the class + # checks like @app_commands.guilds and @app_commands.default_permissions can be used above the class - # these will apply to ALL subcommand, subcommands cannot have invidual perms! + # these will apply to all subcommands, subcommands cannot have individual perms. @app_commands.guild_only() class Group(app_commands.Group):
Done.
I know this is old, but do you have anything to add an input in the command, like /ban user:<user> reason:[reason]
with <> being required and [] is optional?
I know this is old, but do you have anything to add an input in the command, like
/ban user:<user> reason:[reason]
with <> being required and [] is optional?
You can give it a default value of something like None
and check that in your function accordingly.
I know this is old, but do you have anything to add an input in the command, like
/ban user:<user> reason:[reason]
with <> being required and [] is optional?You can give it a default value of something like
None
and check that in your function accordingly.
Im actually having trouble with this too haha! How do you read in "the rest of the message" my old way was to just
*args
But now i cant do that because of typing, *args: tuple
doesn't work, nor does str, I'm at my wits end!
It's a shitpost you can ignore it