From ed710d6253e845420642bd2d3a900ce4b0a15a37 Mon Sep 17 00:00:00 2001 From: Damego Date: Tue, 24 Jan 2023 18:14:37 +0500 Subject: [PATCH 1/3] refactor(context): allow edit message from modal; move defer to base --- interactions/client/context.py | 176 +++++++++++++-------------------- 1 file changed, 71 insertions(+), 105 deletions(-) diff --git a/interactions/client/context.py b/interactions/client/context.py index e8e49f139..9dd3b0182 100644 --- a/interactions/client/context.py +++ b/interactions/client/context.py @@ -2,6 +2,7 @@ from datetime import datetime from logging import Logger from typing import TYPE_CHECKING, List, Optional, Tuple, Union +from contextlib import suppress from ..api.error import LibraryException from ..api.models.channel import Channel, Thread @@ -160,6 +161,50 @@ async def get_guild(self) -> Guild: res = await self._client.get_guild(int(self.guild_id)) return Guild(**res, _client=self._client) + async def defer( + self, ephemeral: Optional[bool] = False, edit_origin: Optional[bool] = False + ) -> Message: + """ + .. versionchanged:: 4.4.0 + Now returns the created message object + + This "defers" a component response, allowing up + to a 15-minute delay between invocation and responding. + + :param Optional[bool] ephemeral: Whether the deferred state is hidden or not. + :param Optional[bool] edit_origin: Whether you want to edit the original message or send a followup message + :return: The deferred message + :rtype: Message + """ + if edit_origin and self.type in {InteractionType.APPLICATION_COMMAND, InteractionType.APPLICATION_COMMAND_AUTOCOMPLETE}: + raise LibraryException(message="You cannot defer with edit_origin parameter in this type of interaction") + + if not self.responded: + self.deferred = True + is_ephemeral: int = MessageFlags.EPHEMERAL.value if bool(ephemeral) else 0 + # ephemeral doesn't change callback typings. just data json + self.callback = ( + InteractionCallbackType.DEFERRED_UPDATE_MESSAGE + if edit_origin + else 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": is_ephemeral}}, + ) + + with suppress(LibraryException): + res = await self._client.get_original_interaction_response( + self.token, str(self.application_id) + ) + self.message = Message(**res, _client=self._client) + + self.responded = True + + return self.message + async def send( self, content: Optional[str] = MISSING, @@ -301,6 +346,9 @@ async def edit( :return: The edited message. """ + if self.message is None: + raise LibraryException(message="There is no message to edit.") + payload = {} if self.message.content is not None or content is not MISSING: @@ -541,55 +589,23 @@ async def edit( else: self.message = msg = Message(**res, _client=self._client) else: - try: - res = await self._client.edit_interaction_response( - token=self.token, - application_id=str(self.application_id), - data=payload, - files=files, - ) - except LibraryException as e: - if e.code in {10015, 10018}: - log.warning(f"You can't edit hidden messages." f"({e.message}).") - else: - # if its not ephemeral or some other thing. - raise e from e - else: - self.message = msg = Message(**res, _client=self._client) - - return msg if msg is not None else Message(**payload, _client=self._client) - - async def defer(self, ephemeral: Optional[bool] = False) -> Message: - """ - .. versionchanged:: 4.4.0 - Now returns the created message object - - This "defers" an interaction response, allowing up - to a 15-minute delay between invocation and responding. - - :param Optional[bool] ephemeral: Whether the deferred state is hidden or not. - :return: The deferred message - :rtype: Message - """ - if not self.responded: - self.deferred = True - _ephemeral: int = MessageFlags.EPHEMERAL.value if ephemeral else 0 - self.callback = InteractionCallbackType.DEFERRED_CHANNEL_MESSAGE_WITH_SOURCE + self.callback = InteractionCallbackType.UPDATE_MESSAGE await self._client.create_interaction_response( + data={"type": self.callback.value, "data": payload}, + files=files, token=self.token, application_id=int(self.id), - data={"type": self.callback.value, "data": {"flags": _ephemeral}}, ) - try: - _msg = await self._client.get_original_interaction_response( + + with suppress(LibraryException): + res = await self._client.get_original_interaction_response( self.token, str(self.application_id) ) - except LibraryException: - pass - else: - self.message = Message(**_msg, _client=self._client) + self.message = msg = Message(**res, _client=self._client) + self.responded = True - return self.message + + return msg or Message(**payload, _client=self._client) async def send(self, content: Optional[str] = MISSING, **kwargs) -> Message: payload, files = await super().send(content, **kwargs) @@ -616,25 +632,21 @@ async def send(self, content: Optional[str] = MISSING, **kwargs) -> Message: files=files, ) - try: - _msg = await self._client.get_original_interaction_response( + with suppress(LibraryException): + res = await self._client.get_original_interaction_response( self.token, str(self.application_id) ) - except LibraryException: - pass - else: - self.message = msg = Message(**_msg, _client=self._client) + self.message = msg = Message(**res, _client=self._client) self.responded = True - if msg is not None: - return msg - return Message( + return msg or Message( **payload, _client=self._client, author={"_client": self._client, "id": None, "username": None, "discriminator": None}, ) + async def populate(self, choices: Union[Choice, List[Choice]]) -> List[Choice]: """ This "populates" the list of choices that the client-end @@ -712,14 +724,12 @@ async def edit(self, content: Optional[str] = MISSING, **kwargs) -> Message: application_id=int(self.id), ) - try: - _msg = await self._client.get_original_interaction_response( + with suppress(LibraryException): + res = await self._client.get_original_interaction_response( self.token, str(self.application_id) ) - except LibraryException: - pass - else: - self.message = msg = Message(**_msg, _client=self._client) + + self.message = msg = Message(**res, _client=self._client) self.responded = True elif self.callback != InteractionCallbackType.DEFERRED_UPDATE_MESSAGE: @@ -739,7 +749,7 @@ async def edit(self, content: Optional[str] = MISSING, **kwargs) -> Message: self.responded = True self.message = msg = Message(**res, _client=self._client) - return msg if msg is not None else Message(**payload, _client=self._client) + return msg or Message(**payload, _client=self._client) async def send(self, content: Optional[str] = MISSING, **kwargs) -> Message: payload, files = await super().send(content, **kwargs) @@ -766,60 +776,16 @@ async def send(self, content: Optional[str] = MISSING, **kwargs) -> Message: files=files, ) - try: - _msg = await self._client.get_original_interaction_response( + with suppress(LibraryException): + res = await self._client.get_original_interaction_response( self.token, str(self.application_id) ) - except LibraryException: - pass - else: - self.message = msg = Message(**_msg, _client=self._client) + self.message = msg = Message(**res, _client=self._client) self.responded = True return msg if msg is not None else Message(**payload, _client=self._client) - async def defer( - self, ephemeral: Optional[bool] = False, edit_origin: Optional[bool] = False - ) -> Message: - """ - .. versionchanged:: 4.4.0 - Now returns the created message object - - This "defers" a component response, allowing up - to a 15-minute delay between invocation and responding. - - :param Optional[bool] ephemeral: Whether the deferred state is hidden or not. - :param Optional[bool] edit_origin: Whether you want to edit the original message or send a followup message - :return: The deferred message - :rtype: Message - """ - if not self.responded: - - self.deferred = True - _ephemeral: int = MessageFlags.EPHEMERAL.value if bool(ephemeral) else 0 - # ephemeral doesn't change callback typings. just data json - 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}}, - ) - try: - _msg = await self._client.get_original_interaction_response( - self.token, str(self.application_id) - ) - except LibraryException: - pass - else: - self.message = Message(**_msg, _client=self._client) - self.responded = True - return self.message - async def disable_all_components( self, respond_to_interaction: Optional[bool] = True, **other_kwargs: Optional[dict] ) -> Message: From 10c62a1309a0b3255834cfeccc6e7ff62d9c000f Mon Sep 17 00:00:00 2001 From: Damego Date: Tue, 24 Jan 2023 18:34:39 +0500 Subject: [PATCH 2/3] refactor: run pre-commit --- interactions/client/context.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/interactions/client/context.py b/interactions/client/context.py index 9dd3b0182..bb078107c 100644 --- a/interactions/client/context.py +++ b/interactions/client/context.py @@ -1,8 +1,8 @@ import asyncio +from contextlib import suppress from datetime import datetime from logging import Logger from typing import TYPE_CHECKING, List, Optional, Tuple, Union -from contextlib import suppress from ..api.error import LibraryException from ..api.models.channel import Channel, Thread @@ -176,8 +176,13 @@ async def defer( :return: The deferred message :rtype: Message """ - if edit_origin and self.type in {InteractionType.APPLICATION_COMMAND, InteractionType.APPLICATION_COMMAND_AUTOCOMPLETE}: - raise LibraryException(message="You cannot defer with edit_origin parameter in this type of interaction") + if edit_origin and self.type in { + InteractionType.APPLICATION_COMMAND, + InteractionType.APPLICATION_COMMAND_AUTOCOMPLETE, + }: + raise LibraryException( + message="You cannot defer with edit_origin parameter in this type of interaction" + ) if not self.responded: self.deferred = True @@ -646,7 +651,6 @@ async def send(self, content: Optional[str] = MISSING, **kwargs) -> Message: author={"_client": self._client, "id": None, "username": None, "discriminator": None}, ) - async def populate(self, choices: Union[Choice, List[Choice]]) -> List[Choice]: """ This "populates" the list of choices that the client-end From a1e6511ab9b6aaa5752307bacc52d3a7ad8369b1 Mon Sep 17 00:00:00 2001 From: Damego Date: Wed, 25 Jan 2023 08:20:24 +0500 Subject: [PATCH 3/3] docs: defer is not only for component --- interactions/client/context.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interactions/client/context.py b/interactions/client/context.py index bb078107c..e4260de61 100644 --- a/interactions/client/context.py +++ b/interactions/client/context.py @@ -168,7 +168,7 @@ async def defer( .. versionchanged:: 4.4.0 Now returns the created message object - This "defers" a component response, allowing up + This "defers" an interaction response, allowing up to a 15-minute delay between invocation and responding. :param Optional[bool] ephemeral: Whether the deferred state is hidden or not.