From 40b2bf62e627d4c9c605cdaff36cf726c3d705f5 Mon Sep 17 00:00:00 2001 From: UK <41271523+NeloBlivion@users.noreply.github.com> Date: Sun, 3 Aug 2025 06:08:19 +0100 Subject: [PATCH 1/4] get_component --- discord/components.py | 69 ++++++++++++++++++++++++++++++++++++++++++- discord/message.py | 28 +++++++++++++++++- discord/ui/view.py | 2 +- 3 files changed, 96 insertions(+), 3 deletions(-) diff --git a/discord/components.py b/discord/components.py index 39576c9eea..ee454cd894 100644 --- a/discord/components.py +++ b/discord/components.py @@ -39,7 +39,7 @@ ) from .flags import AttachmentFlags from .partial_emoji import PartialEmoji, _EmojiTag -from .utils import MISSING, get_slots +from .utils import MISSING, get_slots, find if TYPE_CHECKING: from .emoji import AppEmoji, GuildEmoji @@ -187,6 +187,25 @@ def to_dict(self) -> ActionRowPayload: def walk_components(self) -> Iterator[Component]: yield from self.children + def get_component(self, id: str | int) -> Component | None: + """Get a component from this action row. Roughly equivalent to `utils.get(row.children, ...)`. + If an ``int`` is provided, the component will be retrieved by ``id``, otherwise by ``custom_id``. + + Parameters + ---------- + id: Union[:class:`str`, :class:`int`] + The custom_id or id of the component to get. + + Returns + ------- + Optional[:class:`Component`] + The component with the matching ``id`` or ``custom_id`` if it exists. + """ + if not id: + return None + attr = "id" if isinstance(id, int) else "custom_id" + return find(lambda i: getattr(i, attr, None) == id, self.children) + @classmethod def with_components(cls, *components, id=None): return cls._raw_construct( @@ -620,6 +639,28 @@ def walk_components(self) -> Iterator[Component]: yield from r + [self.accessory] yield from r + def get_component(self, id: str | int) -> Component | None: + """Get a component from this section. Roughly equivalent to `utils.get(section.walk_components(), ...)`. + If an ``int`` is provided, the component will be retrieved by ``id``, otherwise by ``custom_id``. + + Parameters + ---------- + id: Union[:class:`str`, :class:`int`] + The custom_id or id of the component to get. + + Returns + ------- + Optional[:class:`Component`] + The component with the matching ``id`` or ``custom_id`` if it exists. + """ + if not id: + return None + attr = "id" if isinstance(id, int) else "custom_id" + if self.accessory and id == getattr(self.accessory, attr, None): + return self.accessory + component = find(lambda i: getattr(i, attr, None) == id, self.components) + return component + class TextDisplay(Component): """Represents a Text Display from Components V2. @@ -1036,6 +1077,32 @@ def walk_components(self) -> Iterator[Component]: else: yield c + def get_component(self, id: str | int) -> Component | None: + """Get a component from this container. Roughly equivalent to `utils.get(container.components, ...)`. + If an ``int`` is provided, the component will be retrieved by ``id``, otherwise by ``custom_id``. + This method will also search for nested components. + + Parameters + ---------- + id: Union[:class:`str`, :class:`int`] + The custom_id or id of the component to get. + + Returns + ------- + Optional[:class:`Component`] + The component with the matching ``id`` or ``custom_id`` if it exists. + """ + if not id: + return None + attr = "id" if isinstance(id, int) else "custom_id" + component = find(lambda i: getattr(i, attr, None) == id, self.components) + if not component: + for i in self.components: + if hasattr(i, "get_component"): + if component := i.get_component(id): + return component + return component + COMPONENT_MAPPINGS = { 1: ActionRow, diff --git a/discord/message.py b/discord/message.py index 909453c1ad..a460954a56 100644 --- a/discord/message.py +++ b/discord/message.py @@ -59,7 +59,7 @@ from .reaction import Reaction from .sticker import StickerItem from .threads import Thread -from .utils import MISSING, escape_mentions +from .utils import MISSING, escape_mentions, find if TYPE_CHECKING: from .abc import ( @@ -2211,6 +2211,32 @@ def to_message_reference_dict( return data + def get_component(self, id: str | int) -> Component | None: + """Gets a component from this message. Roughly equal to `utils.get(message.components, ...)`. + If an :class:`int` is provided, the component will be retrieved by ``id``, otherwise by ``custom_id``. + This method will also search nested components. + + Parameters + ---------- + id: Union[:class:`str`, :class:`int`] + The id or custom_id the item to get + + Returns + ------- + Optional[:class:`Component`] + The component with the matching ``custom_id`` or ``id`` if it exists. + """ + if not id: + return None + attr = "id" if isinstance(id, int) else "custom_id" + component = find(lambda i: getattr(i, attr, None) == id, self.components) + if not component: + for i in self.components: + if hasattr(i, "get_component"): + if component := i.get_component(id): + return component + return component + class PartialMessage(Hashable): """Represents a partial message to aid with working messages when only diff --git a/discord/ui/view.py b/discord/ui/view.py index 64b0520172..0d8ca13a6f 100644 --- a/discord/ui/view.py +++ b/discord/ui/view.py @@ -434,7 +434,7 @@ def get_item(self, custom_id: str | int) -> Item[V] | None: Parameters ---------- - custom_id: :class:`str` + custom_id: Union[:class:`str`, :class:`int`] The custom_id of the item to get Returns From a9809ad743b8bced1563dd3732357f6fa09b194e Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sun, 3 Aug 2025 05:10:23 +0000 Subject: [PATCH 2/4] style(pre-commit): auto fixes from pre-commit.com hooks --- discord/components.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/discord/components.py b/discord/components.py index ee454cd894..41d06c9643 100644 --- a/discord/components.py +++ b/discord/components.py @@ -39,7 +39,7 @@ ) from .flags import AttachmentFlags from .partial_emoji import PartialEmoji, _EmojiTag -from .utils import MISSING, get_slots, find +from .utils import MISSING, find, get_slots if TYPE_CHECKING: from .emoji import AppEmoji, GuildEmoji From 0a6d40588007e5244337a7a89f5ec0654d9ccad1 Mon Sep 17 00:00:00 2001 From: UK <41271523+NeloBlivion@users.noreply.github.com> Date: Sun, 3 Aug 2025 06:14:25 +0100 Subject: [PATCH 3/4] cl --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 718642108d..412e96e2de 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -67,6 +67,8 @@ These changes are available on the `master` branch, but have not yet been releas ([#2817](https://github.com/Pycord-Development/pycord/pull/2817)) - Added role gradients support with `Role.colours` and the `RoleColours` class. ([#2818](https://github.com/Pycord-Development/pycord/pull/2818)) +- Added `get_component` to `Message`, `Section`, `Container` and `ActionRow`. + ([#2849](https://github.com/Pycord-Development/pycord/pull/2849)) ### Fixed From a9093452620ba0abf9bc92e4afce7a8be72fc03e Mon Sep 17 00:00:00 2001 From: UK <41271523+NeloBlivion@users.noreply.github.com> Date: Sun, 3 Aug 2025 17:16:28 +0100 Subject: [PATCH 4/4] single loop --- discord/components.py | 14 +++++++------- discord/message.py | 14 +++++++------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/discord/components.py b/discord/components.py index 41d06c9643..16203da73b 100644 --- a/discord/components.py +++ b/discord/components.py @@ -1095,13 +1095,13 @@ def get_component(self, id: str | int) -> Component | None: if not id: return None attr = "id" if isinstance(id, int) else "custom_id" - component = find(lambda i: getattr(i, attr, None) == id, self.components) - if not component: - for i in self.components: - if hasattr(i, "get_component"): - if component := i.get_component(id): - return component - return component + for i in self.components: + if getattr(i, attr, None) == id: + return i + elif hasattr(i, "get_component"): + if component := i.get_component(id): + return component + return None COMPONENT_MAPPINGS = { diff --git a/discord/message.py b/discord/message.py index a460954a56..6af61b9e12 100644 --- a/discord/message.py +++ b/discord/message.py @@ -2229,13 +2229,13 @@ def get_component(self, id: str | int) -> Component | None: if not id: return None attr = "id" if isinstance(id, int) else "custom_id" - component = find(lambda i: getattr(i, attr, None) == id, self.components) - if not component: - for i in self.components: - if hasattr(i, "get_component"): - if component := i.get_component(id): - return component - return component + for i in self.components: + if getattr(i, attr, None) == id: + return i + elif hasattr(i, "get_component"): + if component := i.get_component(id): + return component + return None class PartialMessage(Hashable):