diff --git a/discord/abc.py b/discord/abc.py index da8e5d37cc..a32f906cd8 100644 --- a/discord/abc.py +++ b/discord/abc.py @@ -1688,7 +1688,7 @@ async def send( if view.is_dispatchable(): state.store_view(view, ret.id) view.message = ret - view.refresh(ret.components) + view._refresh(ret.components) if delete_after is not None: await ret.delete(delay=delete_after) diff --git a/discord/interactions.py b/discord/interactions.py index 47498c6946..530cb8777f 100644 --- a/discord/interactions.py +++ b/discord/interactions.py @@ -597,8 +597,9 @@ async def edit_original_response( previous_allowed_mentions=previous_mentions, suppress=suppress, ) - if view and self.message: - self._state.prevent_view_updates_for(self.message.id) + _message = self.message or self._original_response + if view and _message: + self._state.prevent_view_updates_for(_message.id) adapter = async_context.get() http = self._state.http data = await adapter.edit_original_interaction_response( @@ -617,7 +618,7 @@ async def edit_original_response( message = InteractionMessage(state=state, channel=self.channel, data=data) # type: ignore if view: if not view.is_finished(): - view.refresh(message.components) + view._refresh(message.components) if view.is_dispatchable(): self._state.store_view(view, message.id) @@ -1191,7 +1192,7 @@ async def edit_message( raise InteractionResponded(self._parent) parent = self._parent - msg = parent.message + msg = parent.message or parent._original_response state = parent._state message_id = msg.id if msg else None if parent.type not in (InteractionType.component, InteractionType.modal_submit): diff --git a/discord/message.py b/discord/message.py index 2ef90bdd9e..2f13274a36 100644 --- a/discord/message.py +++ b/discord/message.py @@ -1882,7 +1882,7 @@ async def edit( if view and not view.is_finished(): view.message = message - view.refresh(message.components) + view._refresh(message.components) if view.is_dispatchable(): self._state.store_view(view, self.id) @@ -2551,7 +2551,7 @@ async def edit(self, **fields: Any) -> Message | None: msg = self._state.create_message(channel=self.channel, data=data) # type: ignore if view and not view.is_finished(): view.message = msg - view.refresh(msg.components) + view._refresh(msg.components) if view.is_dispatchable(): self._state.store_view(view, self.id) return msg diff --git a/discord/ui/modal.py b/discord/ui/modal.py index 8620cec363..71b3269fad 100644 --- a/discord/ui/modal.py +++ b/discord/ui/modal.py @@ -360,7 +360,7 @@ def remove_item(self, item: InputText) -> Self: pass return self - def refresh(self, interaction: Interaction, data: list[ComponentPayload]): + def _refresh(self, interaction: Interaction, data: list[ComponentPayload]): components = [ component for parent_component in data @@ -444,7 +444,7 @@ def add_item(self, item: ModalItem) -> Self: super().add_item(item) return self - def refresh(self, interaction: Interaction, data: list[ComponentPayload]): + def _refresh(self, interaction: Interaction, data: list[ComponentPayload]): for component, child in zip(data, self.children): child.refresh_from_modal(interaction, component) @@ -516,7 +516,7 @@ async def dispatch(self, user_id: int, custom_id: str, interaction: Interaction) try: components = interaction.data["components"] - modal.refresh(interaction, components) + modal._refresh(interaction, components) await modal.callback(interaction) self.remove_modal(modal, user_id) except Exception as e: diff --git a/discord/ui/view.py b/discord/ui/view.py index ec4c0cd8a7..9b1da0ee9d 100644 --- a/discord/ui/view.py +++ b/discord/ui/view.py @@ -26,6 +26,7 @@ from __future__ import annotations import asyncio +import logging import os import sys import time @@ -75,6 +76,8 @@ from ..state import ConnectionState from ..types.components import Component as ComponentPayload +_log = logging.getLogger(__name__) + V = TypeVar("V", bound="BaseView", covariant=True) @@ -726,7 +729,7 @@ def clear_items(self) -> None: self.__weights.clear() return self - def refresh(self, components: list[Component]): + def _refresh(self, components: list[Component]): # This is pretty hacky at the moment old_state: dict[tuple[int, str], ViewItem[V]] = { (item.type.value, item.custom_id): item for item in self.children if item.is_dispatchable() # type: ignore @@ -895,7 +898,7 @@ def add_item(self, item: ViewItem[V]) -> Self: super().add_item(item) return self - def refresh(self, components: list[Component]): + def _refresh(self, components: list[Component]): # Refreshes view data using discord's values # Assumes the components and items are identical if not components: @@ -996,4 +999,9 @@ def update_from_message(self, message_id: int, components: list[ComponentPayload # pre-req: is_message_tracked == true view = self._synced_message_views[message_id] components = [_component_factory(d, state=self._state) for d in components] - view.refresh(components) + try: + view._refresh(components) + except: + _log.warning( + f"Failed to refresh View {view} from Message {message_id} due to mismatched state. Items may not have complete data." + ) diff --git a/discord/webhook/async_.py b/discord/webhook/async_.py index c9093f7781..af4d39e537 100644 --- a/discord/webhook/async_.py +++ b/discord/webhook/async_.py @@ -1902,7 +1902,7 @@ async def send( if self.parent and not view.parent: view.parent = self.parent if msg: - view.refresh(msg.components) + view._refresh(msg.components) if view.is_dispatchable(): self._state.store_view(view, message_id) @@ -2113,7 +2113,7 @@ async def edit_message( message = self._create_message(data) if view and not view.is_finished(): view.message = message - view.refresh(message.components) + view._refresh(message.components) if view.is_dispatchable(): self._state.store_view(view, message_id) return message