diff --git a/disnake/ui/_types.py b/disnake/ui/_types.py index 6bf5066b96..c4713d1a17 100644 --- a/disnake/ui/_types.py +++ b/disnake/ui/_types.py @@ -3,13 +3,14 @@ from __future__ import annotations from collections.abc import Sequence -from typing import TYPE_CHECKING, Any, TypeAlias, Union +from typing import TYPE_CHECKING, Any, Protocol, TypeAlias, Union from typing_extensions import ParamSpec, TypeVar if TYPE_CHECKING: from typing import TypeAlias + from ..components import MessageTopLevelComponent as MessageTopLevelRawComponent from . import ( ActionRow, Button, @@ -97,3 +98,8 @@ ActionRowModalComponent, # deprecated ModalTopLevelComponent_, ] + + +class MessageWithComponents(Protocol): + @property + def components(self) -> Sequence[MessageTopLevelRawComponent]: ... diff --git a/disnake/ui/action_row.py b/disnake/ui/action_row.py index d3841a6753..decaac1c87 100644 --- a/disnake/ui/action_row.py +++ b/disnake/ui/action_row.py @@ -50,6 +50,7 @@ ActionRowModalComponent, ComponentInput, MessageTopLevelComponent, + MessageWithComponents, NonActionRowChildT, ) from .button import Button @@ -77,7 +78,6 @@ from ..abc import AnyChannel from ..emoji import Emoji from ..member import Member - from ..message import Message from ..partial_emoji import PartialEmoji from ..role import Role from ..types.components import ( @@ -877,7 +877,7 @@ def with_message_components(cls, *, id: int = 0) -> ActionRow[ActionRowMessageCo @classmethod def rows_from_message( cls, - message: Message, + message: MessageWithComponents, *, strict: bool = True, ) -> list[ActionRow[ActionRowMessageComponent]]: @@ -895,7 +895,7 @@ def rows_from_message( Parameters ---------- - message: :class:`disnake.Message` + message: :class:`~disnake.Message` | :class:`~disnake.ForwardedMessage` The message from which to extract the components. strict: :class:`bool` Whether or not to raise an exception if an unknown component type is encountered. @@ -1096,7 +1096,7 @@ def walk_components(components: Sequence[ComponentT]) -> Iterator[ComponentT]: yield from _walk_internal(item, seen) -def components_from_message(message: Message) -> list[MessageTopLevelComponent]: +def components_from_message(message: MessageWithComponents) -> list[MessageTopLevelComponent]: r"""Create a list of :class:`UIComponent`\s from the components of an existing message. This will abide by existing component format on the message, including component @@ -1107,7 +1107,7 @@ def components_from_message(message: Message) -> list[MessageTopLevelComponent]: Parameters ---------- - message: :class:`disnake.Message` + message: :class:`~disnake.Message` | :class:`~disnake.ForwardedMessage` The message from which to extract the components. Raises diff --git a/disnake/ui/view.py b/disnake/ui/view.py index ab8d681298..3195bfd09d 100644 --- a/disnake/ui/view.py +++ b/disnake/ui/view.py @@ -32,9 +32,9 @@ from typing_extensions import Self from ..interactions import MessageInteraction - from ..message import Message from ..state import ConnectionState from ..types.components import ActionRow as ActionRowPayload, Component as ComponentPayload + from ._types import MessageWithComponents from .item import ItemCallbackType @@ -194,7 +194,9 @@ def key(item: Item[Self]) -> int: return components @classmethod - def from_message(cls, message: Message, /, *, timeout: float | None = 180.0) -> View: + def from_message( + cls, message: MessageWithComponents, /, *, timeout: float | None = 180.0 + ) -> View: """Converts a message's components into a :class:`View`. The :attr:`.Message.components` of a message are read-only @@ -204,7 +206,7 @@ def from_message(cls, message: Message, /, *, timeout: float | None = 180.0) -> Parameters ---------- - message: :class:`disnake.Message` + message: :class:`~disnake.Message` | :class:`~disnake.ForwardedMessage` The message with components to convert into a view. timeout: :class:`float` | :data:`None` The timeout of the converted view.