From 9fc4769b18ada54b8893476d5cc522abc0c9c779 Mon Sep 17 00:00:00 2001 From: "I. Ahmad" <54180221+nerdguyahmad@users.noreply.github.com> Date: Tue, 21 Jun 2022 17:38:56 -0700 Subject: [PATCH] Add extras attribute to app commands command types --- discord/app_commands/commands.py | 39 ++++++++++++++++++++++++++++++-- discord/app_commands/tree.py | 11 ++++++++- 2 files changed, 47 insertions(+), 3 deletions(-) diff --git a/discord/app_commands/commands.py b/discord/app_commands/commands.py index 457fecafe..2382e2a10 100644 --- a/discord/app_commands/commands.py +++ b/discord/app_commands/commands.py @@ -492,6 +492,9 @@ class Command(Generic[GroupT, P, T]): Due to a Discord limitation, this does not work on subcommands. parent: Optional[:class:`Group`] The parent application command. ``None`` if there isn't one. + extras: :class:`dict` + A dictionary that can be used to store extraneous data. + The library will not touch any values or keys within this dictionary. """ def __init__( @@ -503,6 +506,7 @@ class Command(Generic[GroupT, P, T]): nsfw: bool = False, parent: Optional[Group] = None, guild_ids: Optional[List[int]] = None, + extras: dict = MISSING, ): self.name: str = validate_name(name) self.description: str = description @@ -530,6 +534,7 @@ class Command(Generic[GroupT, P, T]): ) self.guild_only: bool = getattr(callback, '__discord_app_commands_guild_only__', False) self.nsfw: bool = nsfw + self.extras: dict = extras or {} if self._guild_ids is not None and self.parent is not None: raise ValueError('child commands cannot have default guilds set, consider setting them in the parent instead') @@ -568,6 +573,7 @@ class Command(Generic[GroupT, P, T]): copy.module = self.module copy.parent = parent copy.binding = bindings.get(self.binding) if self.binding is not None else binding + copy.extras = self.extras if copy._attr and set_on_binding: setattr(copy.binding, copy._attr, copy) @@ -939,6 +945,9 @@ class ContextMenu: is necessary to be thrown to signal failure, then one inherited from :exc:`AppCommandError` should be used. If all the checks fail without propagating an exception, :exc:`CheckFailure` is raised. + extras: :class:`dict` + A dictionary that can be used to store extraneous data. + The library will not touch any values or keys within this dictionary. """ def __init__( @@ -949,6 +958,7 @@ class ContextMenu: type: AppCommandType = MISSING, nsfw: bool = False, guild_ids: Optional[List[int]] = None, + extras: dict = MISSING, ): self.name: str = validate_context_menu_name(name) self._callback: ContextMenuCallback = callback @@ -971,6 +981,7 @@ class ContextMenu: self.nsfw: bool = nsfw self.guild_only: bool = getattr(callback, '__discord_app_commands_guild_only__', False) self.checks: List[Check] = getattr(callback, '__discord_app_commands_checks__', []) + self.extras: dict = extras or {} @property def callback(self) -> ContextMenuCallback: @@ -1115,6 +1126,9 @@ class Group: Due to a Discord limitation, this does not work on subcommands. parent: Optional[:class:`Group`] The parent group. ``None`` if there isn't one. + extras: :class:`dict` + A dictionary that can be used to store extraneous data. + The library will not touch any values or keys within this dictionary. """ __discord_app_commands_group_children__: ClassVar[List[Union[Command[Any, ..., Any], Group]]] = [] @@ -1184,6 +1198,7 @@ class Group: guild_only: bool = MISSING, nsfw: bool = MISSING, default_permissions: Optional[Permissions] = MISSING, + extras: dict = MISSING, ): cls = self.__class__ self.name: str = validate_name(name) if name is not MISSING else cls.__discord_app_commands_group_name__ @@ -1229,6 +1244,7 @@ class Group: self.module = None self._children: Dict[str, Union[Command, Group]] = {} + self.extras: dict = extras or {} bindings: Dict[Group, Group] = {} @@ -1277,6 +1293,7 @@ class Group: copy._attr = self._attr copy._owner_cls = self._owner_cls copy._children = {} + copy.extras = self.extras bindings[self] = copy @@ -1513,6 +1530,7 @@ class Group: name: str = MISSING, description: str = MISSING, nsfw: bool = False, + extras: dict = MISSING, ) -> Callable[[CommandCallback[GroupT, P, T]], Command[GroupT, P, T]]: """Creates an application command under this group. @@ -1527,6 +1545,9 @@ class Group: of the callback shortened to 100 characters. nsfw: :class:`bool` Whether the command is NSFW and should only work in NSFW channels. Defaults to ``False``. + extras: :class:`dict` + A dictionary that can be used to store extraneous data. + The library will not touch any values or keys within this dictionary. """ def decorator(func: CommandCallback[GroupT, P, T]) -> Command[GroupT, P, T]: @@ -1547,6 +1568,7 @@ class Group: callback=func, nsfw=nsfw, parent=self, + extras=extras, ) self.add_command(command) return command @@ -1559,6 +1581,7 @@ def command( name: str = MISSING, description: str = MISSING, nsfw: bool = False, + extras: dict = MISSING, ) -> Callable[[CommandCallback[GroupT, P, T]], Command[GroupT, P, T]]: """Creates an application command from a regular function. @@ -1575,6 +1598,9 @@ def command( Whether the command is NSFW and should only work in NSFW channels. Defaults to ``False``. Due to a Discord limitation, this does not work on subcommands. + extras: :class:`dict` + A dictionary that can be used to store extraneous data. + The library will not touch any values or keys within this dictionary. """ def decorator(func: CommandCallback[GroupT, P, T]) -> Command[GroupT, P, T]: @@ -1595,12 +1621,18 @@ def command( callback=func, parent=None, nsfw=nsfw, + extras=extras, ) return decorator -def context_menu(*, name: str = MISSING, nsfw: bool = False) -> Callable[[ContextMenuCallback], ContextMenu]: +def context_menu( + *, + name: str = MISSING, + nsfw: bool = False, + extras: dict = MISSING, +) -> Callable[[ContextMenuCallback], ContextMenu]: """Creates an application command context menu from a regular function. This function must have a signature of :class:`~discord.Interaction` as its first parameter @@ -1630,6 +1662,9 @@ def context_menu(*, name: str = MISSING, nsfw: bool = False) -> Callable[[Contex Whether the command is NSFW and should only work in NSFW channels. Defaults to ``False``. Due to a Discord limitation, this does not work on subcommands. + extras: :class:`dict` + A dictionary that can be used to store extraneous data. + The library will not touch any values or keys within this dictionary. """ def decorator(func: ContextMenuCallback) -> ContextMenu: @@ -1637,7 +1672,7 @@ def context_menu(*, name: str = MISSING, nsfw: bool = False) -> Callable[[Contex raise TypeError('context menu function must be a coroutine function') actual_name = func.__name__.title() if name is MISSING else name - return ContextMenu(name=actual_name, nsfw=nsfw, callback=func) + return ContextMenu(name=actual_name, nsfw=nsfw, callback=func, extras=extras) return decorator diff --git a/discord/app_commands/tree.py b/discord/app_commands/tree.py index 75513f48c..2000e99bf 100644 --- a/discord/app_commands/tree.py +++ b/discord/app_commands/tree.py @@ -837,6 +837,7 @@ class CommandTree(Generic[ClientT]): nsfw: bool = False, guild: Optional[Snowflake] = MISSING, guilds: Sequence[Snowflake] = MISSING, + extras: dict = MISSING, ) -> Callable[[CommandCallback[Group, P, T]], Command[Group, P, T]]: """Creates an application command directly under this tree. @@ -860,6 +861,9 @@ class CommandTree(Generic[ClientT]): The list of guilds to add the command to. This cannot be mixed with the ``guild`` parameter. If no guilds are given at all then it becomes a global command instead. + extras: :class:`dict` + A dictionary that can be used to store extraneous data. + The library will not touch any values or keys within this dictionary. """ def decorator(func: CommandCallback[Group, P, T]) -> Command[Group, P, T]: @@ -880,6 +884,7 @@ class CommandTree(Generic[ClientT]): callback=func, nsfw=nsfw, parent=None, + extras=extras, ) self.add_command(command, guild=guild, guilds=guilds) return command @@ -893,6 +898,7 @@ class CommandTree(Generic[ClientT]): nsfw: bool = False, guild: Optional[Snowflake] = MISSING, guilds: Sequence[Snowflake] = MISSING, + extras: dict = MISSING, ) -> Callable[[ContextMenuCallback], ContextMenu]: """Creates a application command context menu from a regular function directly under this tree. @@ -930,6 +936,9 @@ class CommandTree(Generic[ClientT]): The list of guilds to add the command to. This cannot be mixed with the ``guild`` parameter. If no guilds are given at all then it becomes a global command instead. + extras: :class:`dict` + A dictionary that can be used to store extraneous data. + The library will not touch any values or keys within this dictionary. """ def decorator(func: ContextMenuCallback) -> ContextMenu: @@ -937,7 +946,7 @@ class CommandTree(Generic[ClientT]): raise TypeError('context menu function must be a coroutine function') actual_name = func.__name__.title() if name is MISSING else name - context_menu = ContextMenu(name=actual_name, nsfw=nsfw, callback=func) + context_menu = ContextMenu(name=actual_name, nsfw=nsfw, callback=func, extras=extras) self.add_command(context_menu, guild=guild, guilds=guilds) return context_menu