diff --git a/interactions/context.py b/interactions/context.py index a3702edb3..ee0ad320b 100644 --- a/interactions/context.py +++ b/interactions/context.py @@ -17,7 +17,7 @@ log: Logger = get_logger("context") -class Context(DictSerializerMixin): +class _Context(DictSerializerMixin): """ The base class of "context" for dispatched event data from the gateway. The premise of having this class is so @@ -32,93 +32,34 @@ class Context(DictSerializerMixin): :ivar Optional[Guild] guild: The guild data model. """ - __slots__ = ("message", "member", "author", "user", "channel", "guild", "client") - - def __init__(self, **kwargs) -> None: - super().__init__(**kwargs) - self.message = ( - Message(**self.message, _client=self.client) if self._json.get("message") else None - ) - self.member = ( - Member(**self.member, _client=self.client) if self._json.get("member") else None - ) - self.author = self.member - self.user = User(**self.user) if self._json.get("user") else None - - if guild := self._json.get("guild"): - self.guild = Guild(**guild) - elif self.guild_id is None: - self.guild = None - elif guild := self.client.cache.guilds.get(self.guild_id): - self.guild = guild - else: - self.guild = MISSING - - if channel := self._json.get("channel"): - self.channel = Channel(**channel) - elif channel := self.client.cache.channels.get(self.channel_id): - self.channel = channel - else: - self.channel = MISSING - - -class CommandContext(Context): - """ - A derivation of :class:`interactions.context.Context` - designed specifically for application command data. - - .. warning:: - The ``guild`` attribute of the base context - is not accessible for any interaction-related events - since the current Discord API schema does not return - this as a value, but instead ``guild_id``. You will - need to manually fetch for this data for the time being. - - You can fetch with ``client.get_guild(guild_id)`` which - will return a JSON dictionary, which you can then use - ``interactions.Guild(**data)`` for an object or continue - with a dictionary for your own purposes. - - :ivar Snowflake id: The ID of the interaction. - :ivar Snowflake application_id: The application ID of the interaction. - :ivar InteractionType type: The type of interaction. - :ivar InteractionData data?: The application command data. - :ivar Optional[Union[Message, Member, User]] target: The target selected if this interaction is invoked as a context menu. - :ivar str token: The token of the interaction response. - :ivar Snowflake guild_id?: The ID of the current guild. - :ivar Snowflake channel_id?: The ID of the current channel. - :ivar bool responded: Whether an original response was made or not. - :ivar bool deferred: Whether the response was deferred or not. - :ivar str locale?: The selected language of the user invoking the interaction. - :ivar str guild_locale?: The guild's preferred language, if invoked in a guild. - """ - __slots__ = ( "message", "member", "author", "user", "channel", + "channel_id", "guild", + "guild_id", "client", "id", "application_id", - "callback", "type", "data", - "target", - "version", "token", - "guild_id", - "channel_id", - "responded", - "deferred", - "locale", - "guild_locale", ) def __init__(self, **kwargs) -> None: super().__init__(**kwargs) + self.message = ( + Message(**self.message, _client=self.client) if self._json.get("message") else None + ) + self.member = ( + Member(**self.member, _client=self.client) if self._json.get("member") else None + ) + self.author = self.member + self.user = User(**self.user) if self._json.get("user") else None + self.id = Snowflake(self.id) if self._json.get("id") else None self.application_id = ( Snowflake(self.application_id) if self._json.get("application_id") else None @@ -129,47 +70,48 @@ def __init__(self, **kwargs) -> None: self.type = InteractionType(self.type) self.data = InteractionData(**self.data) if self._json.get("data") else None - if self._json.get("data").get("target_id"): - self.target = str(self.data.target_id) + if guild := self._json.get("guild"): + self.guild = Guild(**guild) + elif self.guild_id is None: + self.guild = None + elif guild := self.client.cache.guilds.get(self.guild_id): + self.guild = guild + else: + self.guild = MISSING - if self.data.type == 2: - if ( - self._json.get("guild_id") - and str(self.data.target_id) in self.data.resolved.members - ): - # member id would have potential to exist, and therefore have target def priority. - self.target = self.data.resolved.members[self.target] - else: - self.target = self.data.resolved.users[self.target] - elif self.data.type == 3: - self.target = self.data.resolved.messages[self.target] + if channel := self._json.get("channel"): + self.channel = Channel(**channel) + elif channel := self.client.cache.channels.get(self.channel_id): + self.channel = channel + else: + self.channel = MISSING self.responded = False self.deferred = False - async def defer(self, ephemeral: Optional[bool] = False) -> None: + async def get_channel(self) -> Channel: """ - This "defers" an interaction response, allowing up - to a 15-minute delay between invocation and responding. + This gets the channel the context was invoked in. - :param ephemeral?: Whether the deferred state is hidden or not. - :type ephemeral: Optional[bool] + :return: The channel as object + :rtype: Channel """ - self.deferred = True - _ephemeral: int = (1 << 6) if ephemeral else 0 - if self.type == InteractionType.MESSAGE_COMPONENT: - self.callback = InteractionCallbackType.DEFERRED_UPDATE_MESSAGE - elif self.type in [ - InteractionType.APPLICATION_COMMAND, - InteractionType.MODAL_SUBMIT, - ]: - self.callback = InteractionCallbackType.DEFERRED_CHANNEL_MESSAGE_WITH_SOURCE - await self.client.create_interaction_response( - token=self.token, - application_id=int(self.id), - data={"type": self.callback.value, "data": {"flags": _ephemeral}}, - ) + res = await self.client.get_channel(int(self.channel_id)) + self.channel = Channel(**res, _client=self.client) + return self.channel + + async def get_guild(self) -> Guild: + """ + This gets the guild the context was invoked in. + + :return: The guild as object + :rtype: Guild + """ + + res = await self.client.get_guild(int(self.guild_id)) + self.guild = Guild(**res, _client=self.client) + return self.guild async def send( self, @@ -329,11 +271,7 @@ async def send( else [] ) - elif ( - components is MISSING - and self.message - and self.callback == InteractionCallbackType.DEFERRED_UPDATE_MESSAGE - ): + elif self.message and self.callback == InteractionCallbackType.DEFERRED_UPDATE_MESSAGE: if isinstance(self.message.components, list): _components = [component._json for component in self.message.components] else: @@ -344,17 +282,6 @@ async def send( _ephemeral: int = (1 << 6) if ephemeral else 0 - if not self.deferred and self.type != InteractionType.MESSAGE_COMPONENT: - self.callback = ( - InteractionCallbackType.CHANNEL_MESSAGE_WITH_SOURCE - if self.type == InteractionType.APPLICATION_COMMAND - or self.type == InteractionType.MODAL_SUBMIT - else InteractionCallbackType.UPDATE_MESSAGE - ) - - if not self.deferred and self.type == InteractionType.MESSAGE_COMPONENT: - self.callback = InteractionCallbackType.CHANNEL_MESSAGE_WITH_SOURCE - # TODO: post-v4: Add attachments into Message obj. payload: Message = Message( content=_content, @@ -368,57 +295,7 @@ async def send( ) self.message = payload self.message._client = self.client - _payload: dict = {"type": self.callback.value, "data": payload._json} - - async def func(): - msg = None - if ( - self.responded - or self.deferred - or self.type == InteractionType.MESSAGE_COMPONENT - and self.callback == InteractionCallbackType.DEFERRED_UPDATE_MESSAGE - ): - if ( - self.type == InteractionType.APPLICATION_COMMAND - or self.type == InteractionType.MODAL_SUBMIT - and self.deferred - or self.type == InteractionType.MESSAGE_COMPONENT - and self.deferred - ): - res = await self.client.edit_interaction_response( - data=payload._json, - token=self.token, - application_id=str(self.application_id), - ) - self.responded = True - msg = Message(**res, _client=self.client) - self.message = msg - else: - await self.client._post_followup( - data=payload._json, - token=self.token, - application_id=str(self.application_id), - ) - else: - await self.client.create_interaction_response( - token=self.token, - application_id=int(self.id), - data=_payload, - ) - __newdata = await self.client.edit_interaction_response( - data={}, - token=self.token, - application_id=str(self.application_id), - ) - if not __newdata.get("code"): - # if sending message fails somehow - msg = Message(**__newdata, _client=self.client) - self.message = msg - self.responded = True - - return msg or payload - - return await func() + return payload async def edit( self, @@ -469,7 +346,7 @@ async def edit( _allowed_mentions: dict = {} if allowed_mentions is MISSING else allowed_mentions _message_reference: dict = {} if message_reference is MISSING else message_reference._json - payload["allowed_mnentions"] = _allowed_mentions + payload["allowed_mentions"] = _allowed_mentions payload["message_reference"] = _message_reference if self.message.components is not None or components is not MISSING: @@ -586,79 +463,218 @@ async def edit( payload["components"] = _components - async def func(): - if not self.deferred and self.type == InteractionType.MESSAGE_COMPONENT: - self.callback = InteractionCallbackType.UPDATE_MESSAGE - await self.client.create_interaction_response( - data={"type": self.callback.value, "data": payload}, - token=self.token, - application_id=int(self.id), - ) - self.message = Message(**payload, _client=self.client) - self.responded = True - elif self.deferred: + payload = Message(**payload) + self.message = payload + self.message._client = self.client + + return payload + + async def popup(self, modal: Modal) -> None: + """ + This "pops up" a modal to present information back to the + user. + + :param modal: The components you wish to show. + :type modal: Modal + """ + + payload: dict = { + "type": InteractionCallbackType.MODAL.value, + "data": { + "title": modal.title, + "components": modal._json.get("components"), + "custom_id": modal.custom_id, + }, + } + + await self.client.create_interaction_response( + token=self.token, + application_id=int(self.id), + data=payload, + ) + self.responded = True + + return payload + + +class CommandContext(_Context): + """ + A derivation of :class:`interactions.context.Context` + designed specifically for application command data. + + .. warning:: + The ``guild`` attribute of the base context + is not accessible for any interaction-related events + since the current Discord API schema does not return + this as a value, but instead ``guild_id``. You will + need to manually fetch for this data for the time being. + + You can fetch with ``client.get_guild(guild_id)`` which + will return a JSON dictionary, which you can then use + ``interactions.Guild(**data)`` for an object or continue + with a dictionary for your own purposes. + + :ivar Snowflake id: The ID of the interaction. + :ivar Snowflake application_id: The application ID of the interaction. + :ivar InteractionType type: The type of interaction. + :ivar str name: The name of the command in the interaction. + :ivar Optional[str] description?: The description of the command in the interaction. + :ivar Optional[List[Option]] options?: The options of the command in the interaction, if any. + :ivar InteractionData data: The application command data. + :ivar str token: The token of the interaction response. + :ivar Snowflake channel_id: The ID of the current channel. + :ivar Snowflake guild_id: The ID of the current guild. + :ivar bool responded: Whether an original response was made or not. + :ivar bool deferred: Whether the response was deferred or not. + :ivar str locale?: The selected language of the user invoking the interaction. + :ivar str guild_locale?: The guild's preferred language, if invoked in a guild. + """ + + __slots__ = ( + "message", + "member", + "author", + "user", + "channel", + "guild", + "client", + "id", + "application_id", + "callback", + "type", + "data", + "target", + "version", + "token", + "guild_id", + "channel_id", + "responded", + "deferred", + # + "locale", + "guild_locale", + ) + + def __init__(self, **kwargs) -> None: + super().__init__(**kwargs) + + if self._json.get("data").get("target_id"): + self.target = str(self.data.target_id) + + if self.data.type == 2: if ( - self.type == InteractionType.MESSAGE_COMPONENT - and self.callback != InteractionCallbackType.DEFERRED_UPDATE_MESSAGE - ): - await self.client._post_followup( - data=payload, - token=self.token, - application_id=str(self.application_id), - ) - elif ( - self.callback == InteractionCallbackType.DEFERRED_UPDATE_MESSAGE - and self.type == InteractionType.MESSAGE_COMPONENT + self._json.get("guild_id") + and str(self.data.target_id) in self.data.resolved.members ): - res = await self.client.edit_interaction_response( - data=payload, - token=self.token, - application_id=str(self.application_id), - ) - self.responded = True - self.message = Message(**res, _client=self.client) - elif hasattr(self.message, "id") and self.message.id is not None: - res = await self.client.edit_message( - int(self.channel_id), int(self.message.id), payload=payload - ) - self.message = Message(**res, _client=self.client) + # member id would have potential to exist, and therefore have target def priority. + self.target = self.data.resolved.members[self.target] else: - res = await self.client.edit_interaction_response( - token=self.token, - application_id=str(self.id), - data={"type": self.callback.value, "data": payload}, - message_id=self.message.id if self.message else "@original", - ) - if res["flags"] == 64: - log.warning("You can't edit hidden messages.") - self.message = payload - self.message._client = self.client - else: - await self.client.edit_message( - int(self.channel_id), res["id"], payload=payload - ) - self.message = Message(**res, _client=self.client) - else: - self.callback = ( - InteractionCallbackType.UPDATE_MESSAGE - if self.type == InteractionType.MESSAGE_COMPONENT - else self.callback + self.target = self.data.resolved.users[self.target] + elif self.data.type == 3: + self.target = self.data.resolved.messages[self.target] + + async def edit(self, content: Optional[str] = MISSING, **kwargs) -> Message: + + payload = await super().edit(content, **kwargs) + + if self.deferred: + if hasattr(self.message, "id") and self.message.id is not None: + res = await self.client.edit_message( + int(self.channel_id), int(self.message.id), payload=payload._json ) + self.message = Message(**res, _client=self.client) + else: res = await self.client.edit_interaction_response( token=self.token, - application_id=str(self.application_id), + application_id=str(self.id), data={"type": self.callback.value, "data": payload._json}, + message_id=self.message.id if self.message else "@original", ) if res["flags"] == 64: log.warning("You can't edit hidden messages.") + self.message = payload + self.message._client = self.client else: await self.client.edit_message( int(self.channel_id), res["id"], payload=payload._json ) self.message = Message(**res, _client=self.client) + else: + res = await self.client.edit_interaction_response( + token=self.token, + application_id=str(self.application_id), + data={"type": self.callback.value, "data": payload._json}, + ) + if res["flags"] == 64: + log.warning("You can't edit hidden messages.") + else: + await self.client.edit_message( + int(self.channel_id), res["id"], payload=payload._json + ) + self.message = Message(**res, _client=self.client) + + return payload + + async def defer(self, ephemeral: Optional[bool] = False) -> None: + """ + This "defers" an interaction response, allowing up + to a 15-minute delay between invocation and responding. + + :param ephemeral?: Whether the deferred state is hidden or not. + :type ephemeral: Optional[bool] + """ + self.deferred = True + _ephemeral: int = (1 << 6) if ephemeral else 0 + self.callback = InteractionCallbackType.DEFERRED_CHANNEL_MESSAGE_WITH_SOURCE + + await self.client.create_interaction_response( + token=self.token, + application_id=int(self.id), + data={"type": self.callback.value, "data": {"flags": _ephemeral}}, + ) + + async def send(self, content: Optional[str] = MISSING, **kwargs) -> Message: + payload = await super().send(content, **kwargs) + + if not self.deferred: + self.callback = InteractionCallbackType.CHANNEL_MESSAGE_WITH_SOURCE + + _payload: dict = {"type": self.callback.value, "data": payload._json} + + msg = None + if self.responded or self.deferred: + if self.deferred: + res = await self.client.edit_interaction_response( + data=payload._json, + token=self.token, + application_id=str(self.application_id), + ) + self.responded = True + self.message = Message(**res, _client=self.client) + else: + await self.client._post_followup( + data=payload._json, + token=self.token, + application_id=str(self.application_id), + ) + else: + await self.client.create_interaction_response( + token=self.token, + application_id=int(self.id), + data=_payload, + ) + __newdata = await self.client.edit_interaction_response( + data={}, + token=self.token, + application_id=str(self.application_id), + ) + if not __newdata.get("code"): + # if sending message fails somehow + msg = Message(**__newdata, _client=self.client) + self.message = msg + self.responded = True - await func() - return self.message + return msg or payload async def delete(self) -> None: """ @@ -722,57 +738,8 @@ async def func(): return await func() - async def popup(self, modal: Modal) -> None: - """ - This "pops up" a modal to present information back to the - user. - - :param modal: The components you wish to show. - :type modal: Modal - """ - - payload: dict = { - "type": InteractionCallbackType.MODAL.value, - "data": { - "title": modal.title, - "components": modal._json.get("components"), - "custom_id": modal.custom_id, - }, - } - - await self.client.create_interaction_response( - token=self.token, - application_id=int(self.id), - data=payload, - ) - self.responded = True - - async def get_channel(self) -> Channel: - """ - This gets the channel the command was invoked in. - - :return: The channel as object - :rtype: Channel - """ - res = await self.client.get_channel(int(self.channel_id)) - self.channel = Channel(**res, _client=self.client) - return self.channel - - async def get_guild(self) -> Guild: - """ - This gets the guild the command was invoked in. - - :return: The guild as object - :rtype: Guild - """ - - res = await self.client.get_guild(int(self.guild_id)) - self.guild = Guild(**res, _client=self.client) - return self.guild - - -class ComponentContext(CommandContext): +class ComponentContext(_Context): """ A derivation of :class:`interactions.context.CommandContext` designed specifically for component data. @@ -808,16 +775,82 @@ def __init__(self, **kwargs) -> None: self.responded = False # remind components that it was not responded to. self.deferred = False # remind components they not have been deferred - @property - def custom_id(self): - return self.data.custom_id + async def edit(self, content: Optional[str] = MISSING, **kwargs) -> Message: - @property - def label(self): - for action_row in self.message.components: - for component in action_row["components"]: - if component["custom_id"] == self.custom_id and component["type"] == 2: - return component.get("label") + payload = await super().edit(content, **kwargs) + + if not self.deferred: + self.callback = InteractionCallbackType.UPDATE_MESSAGE + await self.client.create_interaction_response( + data={"type": self.callback.value, "data": payload._json}, + token=self.token, + application_id=int(self.id), + ) + self.message = payload + self.responded = True + elif self.callback != InteractionCallbackType.DEFERRED_UPDATE_MESSAGE: + await self.client._post_followup( + data=payload._json, + token=self.token, + application_id=str(self.application_id), + ) + else: + res = await self.client.edit_interaction_response( + data=payload._json, + token=self.token, + application_id=str(self.application_id), + ) + self.responded = True + self.message = Message(**res, _client=self.client) + + return payload + + async def send(self, content: Optional[str] = MISSING, **kwargs) -> Message: + payload = await super().send(content, **kwargs) + + if not self.deferred: + self.callback = InteractionCallbackType.CHANNEL_MESSAGE_WITH_SOURCE + + _payload: dict = {"type": self.callback.value, "data": payload._json} + + msg = None + if ( + self.responded + or self.deferred + or self.callback == InteractionCallbackType.DEFERRED_UPDATE_MESSAGE + ): + if self.deferred: + res = await self.client.edit_interaction_response( + data=payload._json, + token=self.token, + application_id=str(self.application_id), + ) + self.responded = True + self.message = Message(**res, _client=self.client) + else: + await self.client._post_followup( + data=payload._json, + token=self.token, + application_id=str(self.application_id), + ) + else: + await self.client.create_interaction_response( + token=self.token, + application_id=int(self.id), + data=_payload, + ) + __newdata = await self.client.edit_interaction_response( + data={}, + token=self.token, + application_id=str(self.application_id), + ) + if not __newdata.get("code"): + # if sending message fails somehow + msg = Message(**__newdata, _client=self.client) + self.message = msg + self.responded = True + + return msg or payload async def defer( self, ephemeral: Optional[bool] = False, edit_origin: Optional[bool] = False @@ -833,15 +866,26 @@ async def defer( """ self.deferred = True _ephemeral: int = (1 << 6) if bool(ephemeral) else 0 + # ephemeral doesn't change callback typings. just data json - if self.type == InteractionType.MESSAGE_COMPONENT: - if edit_origin: - self.callback = InteractionCallbackType.DEFERRED_UPDATE_MESSAGE - else: - self.callback = InteractionCallbackType.DEFERRED_CHANNEL_MESSAGE_WITH_SOURCE + if edit_origin: + self.callback = InteractionCallbackType.DEFERRED_UPDATE_MESSAGE + else: + self.callback = InteractionCallbackType.DEFERRED_CHANNEL_MESSAGE_WITH_SOURCE await self.client.create_interaction_response( token=self.token, application_id=int(self.id), data={"type": self.callback.value, "data": {"flags": _ephemeral}}, ) + + @property + def custom_id(self) -> Optional[str]: + return self.data.custom_id + + @property + def label(self) -> Optional[str]: + for action_row in self.message.components: + for component in action_row["components"]: + if component["custom_id"] == self.custom_id and component["type"] == 2: + return component.get("label") diff --git a/interactions/context.pyi b/interactions/context.pyi index 13ebda295..d696287d8 100644 --- a/interactions/context.pyi +++ b/interactions/context.pyi @@ -1,18 +1,28 @@ -from typing import Any, Dict, List, Optional, Union +from typing import Any, List, Optional, Union -from .api.http import HTTPClient -from .api.models.channel import Channel -from .api.models.guild import Guild -from .api.models.member import Member -from .api.models.message import Embed, Message, MessageInteraction, MessageReference -from .api.models.misc import DictSerializerMixin, Snowflake, MISSING -from .api.models.user import User -from .enums import ComponentType, InteractionCallbackType, InteractionType -from .models.command import Choice -from .models.component import ActionRow, Button, Component, Modal, SelectMenu -from .models.misc import InteractionData +from .api import HTTPClient +from .api.models.channel import Channel as Channel +from .api.models.guild import Guild as Guild +from .api.models.member import Member as Member +from .api.models.message import Embed as Embed +from .api.models.message import Message as Message +from .api.models.message import MessageInteraction as MessageInteraction +from .api.models.message import MessageReference as MessageReference +from .api.models.misc import MISSING as MISSING +from .api.models.misc import DictSerializerMixin as DictSerializerMixin +from .api.models.misc import Snowflake as Snowflake +from .api.models.user import User as User +from .base import get_logger as get_logger +from .enums import InteractionCallbackType as InteractionCallbackType +from .enums import InteractionType as InteractionType +from .models.command import Choice as Choice +from .models.component import ActionRow as ActionRow +from .models.component import Button as Button +from .models.component import Modal as Modal +from .models.component import SelectMenu as SelectMenu +from .models.misc import InteractionData as InteractionData -class Context(DictSerializerMixin): +class _Context(DictSerializerMixin): message: Optional[Message] author: Member member: Member @@ -20,58 +30,103 @@ class Context(DictSerializerMixin): channel: Optional[Channel] guild: Optional[Guild] client: HTTPClient - def __init__(self, **kwargs) -> None: ... - -class CommandContext(Context): id: Snowflake application_id: Snowflake type: InteractionType callback: Optional[InteractionCallbackType] data: InteractionData - target: Optional[Union[Message, Member, User]] version: int token: str guild_id: Snowflake channel_id: Snowflake responded: bool deferred: bool - locale: str - guild_locale: str def __init__(self, **kwargs) -> None: ... - async def defer(self, ephemeral: Optional[bool] = None) -> None: ... + async def get_channel(self) -> Channel: ... + async def get_guild(self) -> Guild: ... async def send( self, content: Optional[str] = MISSING, *, tts: Optional[bool] = MISSING, - # attachments: Optional[List[Any]] = None, # TODO: post-v4: Replace with own file type. embeds: Optional[Union[Embed, List[Embed]]] = MISSING, allowed_mentions: Optional[MessageInteraction] = MISSING, components: Optional[ Union[ActionRow, Button, SelectMenu, List[ActionRow], List[Button], List[SelectMenu]] ] = MISSING, - ephemeral: Optional[bool] = MISSING, + ephemeral: Optional[bool] = False ) -> Message: ... async def edit( self, content: Optional[str] = MISSING, *, tts: Optional[bool] = MISSING, - # attachments: Optional[List[Any]] = None, # TODO: post-v4: Replace with own file type. + embeds: Optional[Union[Embed, List[Embed]]] = MISSING, + allowed_mentions: Optional[MessageInteraction] = MISSING, + message_reference: Optional[MessageReference] = MISSING, + components: Optional[ + Union[ActionRow, Button, SelectMenu, List[ActionRow], List[Button], List[SelectMenu]] + ] = MISSING + ) -> Message: ... + async def popup(self, modal: Modal) -> None: ... + +class CommandContext(_Context): + target: Optional[Union[Message, Member, User]] + def __init__(self, **kwargs) -> None: ... + async def send( + self, + content: Optional[str] = MISSING, + *, + tts: Optional[bool] = MISSING, embeds: Optional[Union[Embed, List[Embed]]] = MISSING, allowed_mentions: Optional[MessageInteraction] = MISSING, components: Optional[ Union[ActionRow, Button, SelectMenu, List[ActionRow], List[Button], List[SelectMenu]] ] = MISSING, + ephemeral: Optional[bool] = False ) -> Message: ... + async def edit( + self, + content: Optional[str] = MISSING, + *, + tts: Optional[bool] = MISSING, + embeds: Optional[Union[Embed, List[Embed]]] = MISSING, + allowed_mentions: Optional[MessageInteraction] = MISSING, + message_reference: Optional[MessageReference] = MISSING, + components: Optional[ + Union[ActionRow, Button, SelectMenu, List[ActionRow], List[Button], List[SelectMenu]] + ] = MISSING + ) -> Message: ... + async def defer(self, ephemeral: Optional[bool] = False) -> None: ... async def delete(self) -> None: ... - async def popup(self, modal: Modal): ... async def populate(self, choices: Union[Choice, List[Choice]]) -> List[Choice]: ... - async def get_channel(self) -> Channel: ... - async def get_guild(self) -> Guild: ... -class ComponentContext(CommandContext): +class ComponentContext(_Context): def __init__(self, **kwargs) -> None: ... - def defer( + async def send( + self, + content: Optional[str] = MISSING, + *, + tts: Optional[bool] = MISSING, + embeds: Optional[Union[Embed, List[Embed]]] = MISSING, + allowed_mentions: Optional[MessageInteraction] = MISSING, + components: Optional[ + Union[ActionRow, Button, SelectMenu, List[ActionRow], List[Button], List[SelectMenu]] + ] = MISSING, + ephemeral: Optional[bool] = False + ) -> Message: ... + async def edit( + self, + content: Optional[str] = MISSING, + *, + tts: Optional[bool] = MISSING, + embeds: Optional[Union[Embed, List[Embed]]] = MISSING, + allowed_mentions: Optional[MessageInteraction] = MISSING, + message_reference: Optional[MessageReference] = MISSING, + components: Optional[ + Union[ActionRow, Button, SelectMenu, List[ActionRow], List[Button], List[SelectMenu]] + ] = MISSING + ) -> Message: ... + async def defer( self, ephemeral: Optional[bool] = False, edit_origin: Optional[bool] = False ) -> None: ...