From a667e67b75d93a2430bbab8cdfef2e387ff7c5d0 Mon Sep 17 00:00:00 2001 From: DA-344 <108473820+DA-344@users.noreply.github.com> Date: Mon, 17 Feb 2025 16:58:04 +0100 Subject: [PATCH] chore: Update based off discussion - See [this message in the #bikeshedding channel on the discord.py Discord server](https://discord.com/channels/336642139381301249/1294389448863125505/1340297281676775485) for details on why. --- discord/interactions.py | 378 ++++++++++---------------------------- discord/webhook/async_.py | 7 +- docs/interactions/api.rst | 18 +- 3 files changed, 100 insertions(+), 303 deletions(-) diff --git a/discord/interactions.py b/discord/interactions.py index 2d444499b..7ab9b5b98 100644 --- a/discord/interactions.py +++ b/discord/interactions.py @@ -55,8 +55,7 @@ __all__ = ( 'InteractionMessage', 'InteractionResponse', 'InteractionCallback', - 'InteractionCallbackResource', - 'InteractionCallbackActivity', + 'InteractionCallbackActivityInstance', ) if TYPE_CHECKING: @@ -66,8 +65,6 @@ if TYPE_CHECKING: ApplicationCommandInteractionData, InteractionCallback as InteractionCallbackPayload, InteractionCallbackActivity as InteractionCallbackActivityPayload, - InteractionCallbackResponse as InteractionCallbackResponsePayload, - InteractionCallbackResource as InteractionCallbackResourcePayload, ) from .types.webhook import ( Webhook as WebhookPayload, @@ -641,8 +638,8 @@ class Interaction(Generic[ClientT]): return await translator.translate(string, locale=locale, context=context) -class InteractionCallbackActivity: - """Represents an activity instance returned by an interaction callback. +class InteractionCallbackActivityInstance: + """Represents an activity instance launched as an interaction response. .. versionadded:: 2.5 @@ -654,159 +651,78 @@ class InteractionCallbackActivity: __slots__ = ('id',) - def __init__(self, *, data: InteractionCallbackActivityPayload) -> None: + def __init__(self, data: InteractionCallbackActivityPayload) -> None: self.id: str = data['id'] - def __repr__(self) -> str: - return f'' - +class InteractionCallback(Generic[ClientT]): + """Represents an interaction response callback. -class InteractionCallback: - """Represents an interaction callback invoking interaction. + .. versionadded:: 2.5 Attributes ---------- id: :class:`int` - The ID of the interaction. - type: :class:`InteractionType` - The interaction response type. - activity_instance_id: Optional[:class:`str`] - The ID of the activity that was launched as response of this interaction. - message_id: Optional[:class:`int`] - The ID of the message that was sent as response of this interaction. - """ - - __slots__ = ( - '_state', - 'id', - '_message', - 'type', - 'activity_instance_id', - 'message_id', - ) - - def __init__(self, *, data: InteractionCallbackResponsePayload, state: ConnectionState) -> None: - self._state: ConnectionState = state - self.id: int = int(data['id']) - self._message: Optional[Message] = None - self._update(data) - - def __repr__(self) -> str: - return f'' - - def _update(self, data: InteractionCallbackResponsePayload) -> None: - self.type: InteractionType = try_enum(InteractionType, data['type']) - self.activity_instance_id: Optional[str] = data.get('activity_instance_id') - self.message_id: Optional[int] = utils._get_as_snowflake(data, 'response_message_id') - - @property - def message(self) -> Optional[Message]: - """Optional[:class:`Message`]: Returns the cached message, or ``None``.""" - return self._message or self._state._get_message(self.message_id) - - -class InteractionCallbackResource(Generic[ClientT]): - """Represents an interaction callback's resource. - - Attributes - ---------- + The interaction ID. type: :class:`InteractionResponseType` The interaction callback response type. - activity: Optional[:class:`InteractionCallbackActivity`] - The activity that was launched as a response to the interaction. - message: Optional[:class:`InteractionMessage`] - The message that was sent as a response to the interaction. + resource: Optional[Union[:class:`InteractionMessage`, :class:`InteractionCallbackActivityInstance`]] + The resource that the interaction response created. If a message was sent, this will be + a :class:`InteractionMessage`, else if an activity was launched this will be a + :class:`InteractionCallbackActivityInstance`. In any other case, this will be ``None``. + message_id: Optional[:class:`int`] + The message ID of the resource. Only available if the resource is a :class:`InteractionMessage`. + activity_id: Optional[:class:`str`] + The activity ID of the resource. Only available if the resource is a :class:`InteractionCallbackActivityInstance`. """ - __slots__ = ( - '_state', - '_parent', - 'activity', - 'message', - 'type', - ) - def __init__( self, *, - data: InteractionCallbackResourcePayload, + data: InteractionCallbackPayload, + parent: Interaction[ClientT], state: ConnectionState, - parent: InteractionCallbackResponse, + type: InteractionResponseType, ) -> None: self._state: ConnectionState = state - self._parent: InteractionCallbackResponse = parent - self.activity: Optional[InteractionCallbackActivity] = None - self.message: Optional[InteractionMessage] = None + self._parent: Interaction[ClientT] = parent + self.type: InteractionResponseType = type self._update(data) - def _update(self, data: InteractionCallbackResourcePayload) -> None: - try: - self.type: InteractionResponseType = try_enum(InteractionResponseType, data['type']) - except KeyError: - pass - - try: - self.activity = InteractionCallbackActivity(data=data['activity_instance']) - except KeyError: - pass - - try: - self.message = InteractionMessage( - state=self._state, - channel=self._parent._parent.channel, # type: ignore - data=data['message'], - ) - except KeyError: - pass - - self._parent.interaction._message = self.message - - -class InteractionCallbackResponse(Generic[ClientT]): - """Represents a Discord response to an interaction. + def _update(self, data: InteractionCallbackPayload) -> None: + interaction = data['interaction'] - .. versionadded:: 2.5 + self.id: int = int(interaction['id']) + self._thinking: bool = interaction.get('response_message_loading', False) + self._ephemeral: bool = interaction.get('response_message_ephemeral', False) - Attributes - ---------- - interaction: :class:`InteractionCallback` - The interaction callback response. - resource: :class:`InteractionCallbackResource` - The interaction callback resource. - """ + self.message_id: Optional[int] = utils._get_as_snowflake(interaction, 'response_message_id') + self.activity_id: Optional[str] = interaction.get('activity_instance_id') - __slots__ = ( - '_parent', - '_state', - 'interaction', - 'resource', - ) + self.resource: Optional[Union[InteractionMessage, InteractionCallbackActivityInstance]] = None - def __init__( - self, - *, - parent: Interaction[ClientT], - data: InteractionCallbackPayload, - ) -> None: - self._parent: Interaction[ClientT] = parent - self._state: ConnectionState = parent._state + if 'resource' in data: + resource = data['resource'] - self.interaction: InteractionCallback = InteractionCallback(data=data['interaction'], state=self._state) - self.resource: Optional[InteractionCallbackResource] = None + self.type = try_enum(InteractionResponseType, resource['type']) - def __repr__(self) -> str: - return f'' + if 'message' in resource and resource['message']: + self.resource = InteractionMessage( + state=self._state, + channel=self._parent.channel, # type: ignore # channel should be the correct type here + data=resource['message'], + ) + elif 'activity_instance' in resource and resource['activity_instance']: + self.resource = InteractionCallbackActivityInstance( + resource['activity_instance'], + ) - def _update(self, data: InteractionCallbackPayload) -> None: - interaction = data['interaction'] - resource = data.get('resource', {}) - self.interaction._update(interaction) - if self.resource: - self.resource._update(resource) # pyright: ignore[reportArgumentType] - else: - self.resource = InteractionCallbackResource(data=resource, state=self._state, parent=self) # type: ignore + def is_thinking(self) -> bool: + """:class:`bool`: Whether the response was a thinking defer.""" + return self._thinking - self._parent._original_response = self.interaction.message # type: ignore + def is_ephemeral(self) -> bool: + """:class:`bool`: Whether the response was ephemeral.""" + return self._ephemeral class InteractionResponse(Generic[ClientT]): @@ -838,33 +754,12 @@ class InteractionResponse(Generic[ClientT]): """:class:`InteractionResponseType`: The type of response that was sent, ``None`` if response is not done.""" return self._response_type - @overload - async def defer( - self, - *, - ephemeral: bool = ..., - thinking: bool = ..., - with_response: Literal[True] = ..., - ) -> InteractionCallbackResponse[ClientT]: - ... - - @overload - async def defer( - self, - *, - ephemeral: bool = ..., - thinking: bool = ..., - with_response: Literal[False] = False, - ) -> None: - ... - async def defer( self, *, ephemeral: bool = False, thinking: bool = False, - with_response: bool = True, - ) -> Optional[InteractionCallbackResponse[ClientT]]: + ) -> Optional[InteractionCallback[ClientT]]: """|coro| Defers the interaction response. @@ -878,6 +773,9 @@ class InteractionResponse(Generic[ClientT]): - :attr:`InteractionType.component` - :attr:`InteractionType.modal_submit` + .. versionchanged:: 2.5 + This now returns a :class:`InteractionCallback` instance. + Parameters ----------- ephemeral: :class:`bool` @@ -889,10 +787,6 @@ class InteractionResponse(Generic[ClientT]): In UI terms, this is represented as if the bot is thinking of a response. It is your responsibility to eventually send a followup message via :attr:`Interaction.followup` to make this thinking state go away. Application commands (AKA Slash commands) cannot use :attr:`InteractionResponseType.deferred_message_update`. - with_response: :class:`bool` - Whether to return the interaction response callback resource. - - .. versionadded:: 2.5 Raises ------- @@ -936,14 +830,14 @@ class InteractionResponse(Generic[ClientT]): proxy=http.proxy, proxy_auth=http.proxy_auth, params=params, - with_response=with_response, ) self._response_type = InteractionResponseType(defer_type) - if response: - return InteractionCallbackResponse( - parent=parent, - data=response, - ) + return InteractionCallback( + data=response, + parent=self._parent, + state=self._parent._state, + type=self._response_type, + ) async def pong(self) -> None: """|coro| @@ -977,48 +871,6 @@ class InteractionResponse(Generic[ClientT]): ) self._response_type = InteractionResponseType.pong - @overload - async def send_message( - self, - content: Optional[Any] = ..., - *, - embed: Embed = ..., - embeds: Sequence[Embed] = ..., - file: File = ..., - files: Sequence[File] = ..., - view: View = ..., - tts: bool = ..., - ephemeral: bool = ..., - allowed_mentions: AllowedMentions = ..., - suppress_embeds: bool = ..., - silent: bool = ..., - delete_after: Optional[float] = ..., - poll: Poll = ..., - with_response: Literal[True] = ..., - ) -> InteractionCallbackResponse[ClientT]: - ... - - @overload - async def send_message( - self, - content: Optional[Any] = ..., - *, - embed: Embed = ..., - embeds: Sequence[Embed] = ..., - file: File = ..., - files: Sequence[File] = ..., - view: View = ..., - tts: bool = ..., - ephemeral: bool = ..., - allowed_mentions: AllowedMentions = ..., - suppress_embeds: bool = ..., - silent: bool = ..., - delete_after: Optional[float] = ..., - poll: Poll = ..., - with_response: Literal[False] = False, - ) -> None: - ... - async def send_message( self, content: Optional[Any] = None, @@ -1035,12 +887,14 @@ class InteractionResponse(Generic[ClientT]): silent: bool = False, delete_after: Optional[float] = None, poll: Poll = MISSING, - with_response: bool = True, - ) -> Optional[InteractionCallbackResponse[ClientT]]: + ) -> InteractionCallback[ClientT]: """|coro| Responds to this interaction by sending a message. + .. versionchanged:: 2.5 + This now returns a :class:`InteractionCallback` instance. + Parameters ----------- content: Optional[:class:`str`] @@ -1083,10 +937,6 @@ class InteractionResponse(Generic[ClientT]): The poll to send with this message. .. versionadded:: 2.4 - with_response: :class:`bool` - Whether to return the interaction response callback resource. - - .. versionadded:: 2.5 Raises ------- @@ -1101,8 +951,8 @@ class InteractionResponse(Generic[ClientT]): Returns ------- - Optional[:class:`InteractionCallback`] - The interaction callback data, or ``None``. + :class:`InteractionCallback` + The interaction callback data. """ if self._response_type: raise InteractionResponded(self._parent) @@ -1140,7 +990,6 @@ class InteractionResponse(Generic[ClientT]): proxy=http.proxy, proxy_auth=http.proxy_auth, params=params, - with_response=with_response, ) if view is not MISSING and not view.is_finished(): @@ -1164,43 +1013,13 @@ class InteractionResponse(Generic[ClientT]): pass asyncio.create_task(inner_call()) - if response: - return InteractionCallbackResponse( - parent=parent, - data=response, - ) - @overload - async def edit_message( - self, - *, - content: Optional[Any] = ..., - embed: Optional[Embed] = ..., - embeds: Sequence[Embed] = ..., - attachments: Sequence[Union[Attachment, File]] = ..., - view: Optional[View] = ..., - allowed_mentions: Optional[AllowedMentions] = ..., - delete_after: Optional[float] = ..., - suppress_embeds: bool = ..., - with_response: Literal[True] = ..., - ) -> InteractionCallbackResponse[ClientT]: - ... - - @overload - async def edit_message( - self, - *, - content: Optional[Any] = ..., - embed: Optional[Embed] = ..., - embeds: Sequence[Embed] = ..., - attachments: Sequence[Union[Attachment, File]] = ..., - view: Optional[View] = ..., - allowed_mentions: Optional[AllowedMentions] = ..., - delete_after: Optional[float] = ..., - suppress_embeds: bool = ..., - with_response: Literal[False] = False, - ) -> None: - ... + return InteractionCallback( + data=response, + parent=self._parent, + state=self._parent._state, + type=self._response_type, + ) async def edit_message( self, @@ -1213,13 +1032,15 @@ class InteractionResponse(Generic[ClientT]): allowed_mentions: Optional[AllowedMentions] = MISSING, delete_after: Optional[float] = None, suppress_embeds: bool = MISSING, - with_response: bool = True, - ) -> Optional[InteractionCallbackResponse[ClientT]]: + ) -> Optional[InteractionCallback[ClientT]]: """|coro| Responds to this interaction by editing the original message of a component or modal interaction. + .. versionchanged:: 2.5 + This now returns a :class:`InteractionCallback` instance. + Parameters ----------- content: Optional[:class:`str`] @@ -1256,10 +1077,6 @@ class InteractionResponse(Generic[ClientT]): Using this parameter requires :attr:`~.Permissions.manage_messages`. .. versionadded:: 2.4 - with_response: :class:`bool` - Whether to return the interaction response callback resource. - - .. versionadded:: 2.5 Raises ------- @@ -1273,7 +1090,7 @@ class InteractionResponse(Generic[ClientT]): Returns ------- Optional[:class:`InteractionCallback`] - The interaction callback data, or ``None``. + The interaction callback data, or ``None`` if editing the message was not possible. """ if self._response_type: raise InteractionResponded(self._parent) @@ -1323,7 +1140,6 @@ class InteractionResponse(Generic[ClientT]): proxy=http.proxy, proxy_auth=http.proxy_auth, params=params, - with_response=with_response, ) if view and not view.is_finished(): @@ -1342,29 +1158,21 @@ class InteractionResponse(Generic[ClientT]): asyncio.create_task(inner_call()) - if response: - return InteractionCallbackResponse( - parent=parent, - data=response, - ) - - @overload - async def send_modal( - self, modal: Modal, /, *, with_response: Literal[True] = ... - ) -> InteractionCallbackResponse[ClientT]: - ... - - @overload - async def send_modal(self, modal: Modal, /, *, with_response: Literal[False] = False) -> None: - ... + return InteractionCallback( + data=response, + parent=self._parent, + state=self._parent._state, + type=self._response_type, + ) - async def send_modal( - self, modal: Modal, /, *, with_response: bool = True - ) -> Optional[InteractionCallbackResponse[ClientT]]: + async def send_modal(self, modal: Modal, /) -> InteractionCallback[ClientT]: """|coro| Responds to this interaction by sending a modal. + .. versionchanged:: 2.5 + This now returns a :class:`InteractionCallback` instance. + Parameters ----------- modal: :class:`~discord.ui.Modal` @@ -1383,8 +1191,8 @@ class InteractionResponse(Generic[ClientT]): Returns ------- - Optional[:class:`InteractionCallback`] - The interaction callback data, or ``None``. + :class:`InteractionCallback` + The interaction callback data. """ if self._response_type: raise InteractionResponded(self._parent) @@ -1402,17 +1210,17 @@ class InteractionResponse(Generic[ClientT]): proxy=http.proxy, proxy_auth=http.proxy_auth, params=params, - with_response=with_response, ) if not modal.is_finished(): self._parent._state.store_view(modal) self._response_type = InteractionResponseType.modal - if response: - return InteractionCallbackResponse( - parent=parent, - data=response, - ) + return InteractionCallback( + data=response, + parent=self._parent, + state=self._parent._state, + type=self._response_type, + ) async def autocomplete(self, choices: Sequence[Choice[ChoiceT]]) -> None: """|coro| diff --git a/discord/webhook/async_.py b/discord/webhook/async_.py index bd6d2e335..b727cdb91 100644 --- a/discord/webhook/async_.py +++ b/discord/webhook/async_.py @@ -437,17 +437,14 @@ class AsyncWebhookAdapter: proxy: Optional[str] = None, proxy_auth: Optional[aiohttp.BasicAuth] = None, params: MultipartParameters, - with_response: bool = MISSING, - ) -> Response[Optional[InteractionCallbackResponsePayload]]: + ) -> Response[InteractionCallbackResponsePayload]: route = Route( 'POST', '/interactions/{webhook_id}/{webhook_token}/callback', webhook_id=interaction_id, webhook_token=token, ) - - if with_response is not MISSING: - request_params = {'with_response': with_response} + request_params = {'with_response': '1'} if params.files: return self.request( diff --git a/docs/interactions/api.rst b/docs/interactions/api.rst index 6ac76285f..0bf69903b 100644 --- a/docs/interactions/api.rst +++ b/docs/interactions/api.rst @@ -28,28 +28,20 @@ InteractionResponse .. autoclass:: InteractionResponse() :members: -InteractionCallbackResource -~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. attributetable:: InteractionCallbackResource - -.. autoclass:: InteractionCallbackResource() - :members: - InteractionCallback -~~~~~~~~~~~~~~~~~~~ +~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. attributetable:: InteractionCallback .. autoclass:: InteractionCallback() :members: -InteractionCallbackActivity -~~~~~~~~~~~~~~~~~~~~~~~~~~~ +InteractionCallbackActivityInstance +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -.. attributetable:: InteractionCallbackActivity +.. attributetable:: InteractionCallbackActivityInstance -.. autoclass:: InteractionCallbackActivity() +.. autoclass:: InteractionCallbackActivityInstance() :members: InteractionMessage