-
Notifications
You must be signed in to change notification settings - Fork 139
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
refactor: store invokable application commands properly #1107
base: master
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have a bunch of mostly minor comments, but overall this looks really cool 👀
Haven't tested much yet - not sure what exactly happened, but something somewhere ended up trying to register subcommands as top-level commands: https://gist.github.com/shiftinv/eddfcae9ca1f34790ced4a5288e3691f |
Also adds `alias_conflict` attribute for backwards compatibility
Fixed this in 1f10a8d |
) | ||
|
||
test_guilds = (None,) if self._test_guilds is None else self._test_guilds | ||
guild_ids = app_command.guild_ids or test_guilds |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should add a note to the .name
and .guild_ids
attributes that any changes after adding the command to the bot (e.g. through @bot.slash_command
, bot.add_cog
, etc.) are not supported and may result in undefined behavior.
I know of one instance where cmd.guild_ids
is modified in a cog constructor, but from what I can tell that'll still work fine even after this change, since it runs before add_cog
gets called.
for app_command in self.__cog_app_commands__: | ||
if isinstance(app_command, InvokableSlashCommand): | ||
bot.remove_slash_command(app_command.name) | ||
elif isinstance(app_command, InvokableUserCommand): | ||
bot.remove_user_command(app_command.name) | ||
elif isinstance(app_command, InvokableMessageCommand): | ||
bot.remove_message_command(app_command.name) | ||
bot._remove_app_commands( | ||
app_command.body.type, app_command.name, guild_ids=app_command.guild_ids | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This doesn't pose an issue right now, but may need to check for SubCommand(Group)
here too.
guild_id: Optional[:class:`int`] | ||
ID of the guild the command is registered to. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
guild_id: Optional[:class:`int`] | |
ID of the guild the command is registered to. | |
guild_id: Optional[:class:`int`] | |
ID of the guild the command is registered to. | |
.. versionadded:: 2.10 |
# localization may be called multiple times for the same command but it's harmless | ||
app_command.body.localize(self.i18n) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As you mentioned in the comment, calling this multiple times is perfectly fine, but could this just be moved out of the loop instead?
guild_id: Optional[:class:`int`] | ||
The ID of the guild from which this command should be removed, | ||
or ``None`` if it's global. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
guild_id: Optional[:class:`int`] | |
The ID of the guild from which this command should be removed, | |
or ``None`` if it's global. | |
guild_id: Optional[:class:`int`] | |
The ID of the guild from which this command should be removed, | |
or ``None`` if it's global. If ``test_guilds`` is specified in the bot constructor, | |
passing ``None`` here will remove the command from those guilds instead. |
|
||
def get_slash_command( | ||
self, name: str | ||
self, name: str, guild_id: Optional[int] = MISSING |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
small nit, same for the two methods below
self, name: str, guild_id: Optional[int] = MISSING | |
self, name: str, *, guild_id: Optional[int] = MISSING |
Summary
Currently,
disnake.ext.commands
framework doesn't allow registering 2 guild commands with the same type and name in different guilds, even though discord API allows to do that (see issue #260). This PR solves this problem.Consequences
all_xxx_commands
attributes ofInteractionBotBase
are now deprecated in favor ofall_app_commands
bot.add_xxx_command
methods are now deprecated in favor ofadd_app_command
bot.remove_xxx_command
methods are now deprecated in favor ofremove_app_command
bot.get_xxx_command
now works in O(1) only ifguild_id
is specified, otherwise it's O(n) where n = len(all_app_commands)bot.get_xxx_command
can be ambiguous ifguild_id
is not specifiedguild_id
ofbot._ordered_unsynced_commands
is now deprecatedNote
The original idea of allowing to insert IDs of app commands to the corresponding invokable objects had to be abandoned. This is due to complications related to copying.
Checklist
pdm lint
pdm pyright