Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,8 @@ These changes are available on the `master` branch, but have not yet been releas
([#2818](https://github.com/Pycord-Development/pycord/pull/2818))
- Added `Interaction.attachment_size_limit`.
([#2854](https://github.com/Pycord-Development/pycord/pull/2854))
- Added `get_component` to `Message`, `Section`, `Container` and `ActionRow`.
([#2849](https://github.com/Pycord-Development/pycord/pull/2849))

### Fixed

Expand Down
69 changes: 68 additions & 1 deletion discord/components.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
)
from .flags import AttachmentFlags
from .partial_emoji import PartialEmoji, _EmojiTag
from .utils import MISSING, get_slots
from .utils import MISSING, find, get_slots

if TYPE_CHECKING:
from .emoji import AppEmoji, GuildEmoji
Expand Down Expand Up @@ -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(
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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"
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 = {
1: ActionRow,
Expand Down
28 changes: 27 additions & 1 deletion discord/message.py
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
Expand Down Expand Up @@ -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"
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):
"""Represents a partial message to aid with working messages when only
Expand Down
2 changes: 1 addition & 1 deletion discord/ui/view.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading