Browse Source

chore: add id attr to components and black item.py

pull/10166/head
DA-344 3 months ago
parent
commit
7601533fe9
  1. 112
      discord/components.py
  2. 5
      discord/ui/action_row.py
  3. 3
      discord/ui/item.py

112
discord/components.py

@ -177,13 +177,18 @@ class ActionRow(Component):
------------ ------------
children: List[Union[:class:`Button`, :class:`SelectMenu`, :class:`TextInput`]] children: List[Union[:class:`Button`, :class:`SelectMenu`, :class:`TextInput`]]
The children components that this holds, if any. The children components that this holds, if any.
id: Optional[:class:`int`]
The ID of this component.
.. versionadded:: 2.6
""" """
__slots__: Tuple[str, ...] = ('children',) __slots__: Tuple[str, ...] = ('children', 'id')
__repr_info__: ClassVar[Tuple[str, ...]] = __slots__ __repr_info__: ClassVar[Tuple[str, ...]] = __slots__
def __init__(self, data: ActionRowPayload, /) -> None: def __init__(self, data: ActionRowPayload, /) -> None:
self.id: Optional[int] = data.get('id')
self.children: List[ActionRowChildComponentType] = [] self.children: List[ActionRowChildComponentType] = []
for component_data in data.get('components', []): for component_data in data.get('components', []):
@ -198,10 +203,13 @@ class ActionRow(Component):
return ComponentType.action_row return ComponentType.action_row
def to_dict(self) -> ActionRowPayload: def to_dict(self) -> ActionRowPayload:
return { payload: ActionRowPayload = {
'type': self.type.value, 'type': self.type.value,
'components': [child.to_dict() for child in self.children], 'components': [child.to_dict() for child in self.children],
} }
if self.id is not None:
payload['id'] = self.id
return payload
class Button(Component): class Button(Component):
@ -235,6 +243,10 @@ class Button(Component):
The SKU ID this button sends you to, if available. The SKU ID this button sends you to, if available.
.. versionadded:: 2.4 .. versionadded:: 2.4
id: Optional[:class:`int`]
The ID of this component.
.. versionadded:: 2.6
""" """
__slots__: Tuple[str, ...] = ( __slots__: Tuple[str, ...] = (
@ -245,11 +257,13 @@ class Button(Component):
'label', 'label',
'emoji', 'emoji',
'sku_id', 'sku_id',
'id',
) )
__repr_info__: ClassVar[Tuple[str, ...]] = __slots__ __repr_info__: ClassVar[Tuple[str, ...]] = __slots__
def __init__(self, data: ButtonComponentPayload, /) -> None: def __init__(self, data: ButtonComponentPayload, /) -> None:
self.id: Optional[int] = data.get('id')
self.style: ButtonStyle = try_enum(ButtonStyle, data['style']) self.style: ButtonStyle = try_enum(ButtonStyle, data['style'])
self.custom_id: Optional[str] = data.get('custom_id') self.custom_id: Optional[str] = data.get('custom_id')
self.url: Optional[str] = data.get('url') self.url: Optional[str] = data.get('url')
@ -278,6 +292,9 @@ class Button(Component):
'disabled': self.disabled, 'disabled': self.disabled,
} }
if self.id is not None:
payload['id'] = self.id
if self.sku_id: if self.sku_id:
payload['sku_id'] = str(self.sku_id) payload['sku_id'] = str(self.sku_id)
@ -329,6 +346,10 @@ class SelectMenu(Component):
Whether the select is disabled or not. Whether the select is disabled or not.
channel_types: List[:class:`.ChannelType`] channel_types: List[:class:`.ChannelType`]
A list of channel types that are allowed to be chosen in this select menu. A list of channel types that are allowed to be chosen in this select menu.
id: Optional[:class:`int`]
The ID of this component.
.. versionadded:: 2.6
""" """
__slots__: Tuple[str, ...] = ( __slots__: Tuple[str, ...] = (
@ -341,6 +362,7 @@ class SelectMenu(Component):
'disabled', 'disabled',
'channel_types', 'channel_types',
'default_values', 'default_values',
'id',
) )
__repr_info__: ClassVar[Tuple[str, ...]] = __slots__ __repr_info__: ClassVar[Tuple[str, ...]] = __slots__
@ -357,6 +379,7 @@ class SelectMenu(Component):
self.default_values: List[SelectDefaultValue] = [ self.default_values: List[SelectDefaultValue] = [
SelectDefaultValue.from_dict(d) for d in data.get('default_values', []) SelectDefaultValue.from_dict(d) for d in data.get('default_values', [])
] ]
self.id: Optional[int] = data.get('id')
def to_dict(self) -> SelectMenuPayload: def to_dict(self) -> SelectMenuPayload:
payload: SelectMenuPayload = { payload: SelectMenuPayload = {
@ -366,6 +389,8 @@ class SelectMenu(Component):
'max_values': self.max_values, 'max_values': self.max_values,
'disabled': self.disabled, 'disabled': self.disabled,
} }
if self.id is not None:
payload['id'] = self.id
if self.placeholder: if self.placeholder:
payload['placeholder'] = self.placeholder payload['placeholder'] = self.placeholder
if self.options: if self.options:
@ -531,6 +556,10 @@ class TextInput(Component):
The minimum length of the text input. The minimum length of the text input.
max_length: Optional[:class:`int`] max_length: Optional[:class:`int`]
The maximum length of the text input. The maximum length of the text input.
id: Optional[:class:`int`]
The ID of this component.
.. versionadded:: 2.6
""" """
__slots__: Tuple[str, ...] = ( __slots__: Tuple[str, ...] = (
@ -542,6 +571,7 @@ class TextInput(Component):
'required', 'required',
'min_length', 'min_length',
'max_length', 'max_length',
'id',
) )
__repr_info__: ClassVar[Tuple[str, ...]] = __slots__ __repr_info__: ClassVar[Tuple[str, ...]] = __slots__
@ -555,6 +585,7 @@ class TextInput(Component):
self.required: bool = data.get('required', True) self.required: bool = data.get('required', True)
self.min_length: Optional[int] = data.get('min_length') self.min_length: Optional[int] = data.get('min_length')
self.max_length: Optional[int] = data.get('max_length') self.max_length: Optional[int] = data.get('max_length')
self.id: Optional[int] = data.get('id')
@property @property
def type(self) -> Literal[ComponentType.text_input]: def type(self) -> Literal[ComponentType.text_input]:
@ -570,6 +601,9 @@ class TextInput(Component):
'required': self.required, 'required': self.required,
} }
if self.id is not None:
payload['id'] = self.id
if self.placeholder: if self.placeholder:
payload['placeholder'] = self.placeholder payload['placeholder'] = self.placeholder
@ -721,11 +755,14 @@ class SectionComponent(Component):
The components on this section. The components on this section.
accessory: :class:`Component` accessory: :class:`Component`
The section accessory. The section accessory.
id: Optional[:class:`int`]
The ID of this component.
""" """
__slots__ = ( __slots__ = (
'components', 'components',
'accessory', 'accessory',
'id',
) )
__repr_info__ = __slots__ __repr_info__ = __slots__
@ -733,6 +770,7 @@ class SectionComponent(Component):
def __init__(self, data: SectionComponentPayload, state: Optional[ConnectionState]) -> None: def __init__(self, data: SectionComponentPayload, state: Optional[ConnectionState]) -> None:
self.components: List[SectionComponentType] = [] self.components: List[SectionComponentType] = []
self.accessory: Component = _component_factory(data['accessory'], state) # type: ignore self.accessory: Component = _component_factory(data['accessory'], state) # type: ignore
self.id: Optional[int] = data.get('id')
for component_data in data['components']: for component_data in data['components']:
component = _component_factory(component_data, state) component = _component_factory(component_data, state)
@ -749,6 +787,10 @@ class SectionComponent(Component):
'components': [c.to_dict() for c in self.components], 'components': [c.to_dict() for c in self.components],
'accessory': self.accessory.to_dict(), 'accessory': self.accessory.to_dict(),
} }
if self.id is not None:
payload['id'] = self.id
return payload return payload
@ -772,12 +814,15 @@ class ThumbnailComponent(Component):
The description shown within this thumbnail. The description shown within this thumbnail.
spoiler: :class:`bool` spoiler: :class:`bool`
Whether this thumbnail is flagged as a spoiler. Whether this thumbnail is flagged as a spoiler.
id: Optional[:class:`int`]
The ID of this component.
""" """
__slots__ = ( __slots__ = (
'media', 'media',
'spoiler', 'spoiler',
'description', 'description',
'id',
) )
__repr_info__ = __slots__ __repr_info__ = __slots__
@ -790,19 +835,25 @@ class ThumbnailComponent(Component):
self.media: UnfurledMediaItem = UnfurledMediaItem._from_data(data['media'], state) self.media: UnfurledMediaItem = UnfurledMediaItem._from_data(data['media'], state)
self.description: Optional[str] = data.get('description') self.description: Optional[str] = data.get('description')
self.spoiler: bool = data.get('spoiler', False) self.spoiler: bool = data.get('spoiler', False)
self.id: Optional[int] = data.get('id')
@property @property
def type(self) -> Literal[ComponentType.thumbnail]: def type(self) -> Literal[ComponentType.thumbnail]:
return ComponentType.thumbnail return ComponentType.thumbnail
def to_dict(self) -> ThumbnailComponentPayload: def to_dict(self) -> ThumbnailComponentPayload:
return { payload = {
'media': self.media.to_dict(), # pyright: ignore[reportReturnType] 'media': self.media.to_dict(),
'description': self.description, 'description': self.description,
'spoiler': self.spoiler, 'spoiler': self.spoiler,
'type': self.type.value, 'type': self.type.value,
} }
if self.id is not None:
payload['id'] = self.id
return payload # type: ignore
class TextDisplay(Component): class TextDisplay(Component):
"""Represents a text display from the Discord Bot UI Kit. """Represents a text display from the Discord Bot UI Kit.
@ -820,24 +871,30 @@ class TextDisplay(Component):
---------- ----------
content: :class:`str` content: :class:`str`
The content that this display shows. The content that this display shows.
id: Optional[:class:`int`]
The ID of this component.
""" """
__slots__ = ('content',) __slots__ = ('content', 'id')
__repr_info__ = __slots__ __repr_info__ = __slots__
def __init__(self, data: TextComponentPayload) -> None: def __init__(self, data: TextComponentPayload) -> None:
self.content: str = data['content'] self.content: str = data['content']
self.id: Optional[int] = data.get('id')
@property @property
def type(self) -> Literal[ComponentType.text_display]: def type(self) -> Literal[ComponentType.text_display]:
return ComponentType.text_display return ComponentType.text_display
def to_dict(self) -> TextComponentPayload: def to_dict(self) -> TextComponentPayload:
return { payload: TextComponentPayload = {
'type': self.type.value, 'type': self.type.value,
'content': self.content, 'content': self.content,
} }
if self.id is not None:
payload['id'] = self.id
return payload
class UnfurledMediaItem(AssetMixin): class UnfurledMediaItem(AssetMixin):
@ -1006,24 +1063,30 @@ class MediaGalleryComponent(Component):
---------- ----------
items: List[:class:`MediaGalleryItem`] items: List[:class:`MediaGalleryItem`]
The items this gallery has. The items this gallery has.
id: Optional[:class:`int`]
The ID of this component.
""" """
__slots__ = ('items',) __slots__ = ('items', 'id')
__repr_info__ = __slots__ __repr_info__ = __slots__
def __init__(self, data: MediaGalleryComponentPayload, state: Optional[ConnectionState]) -> None: def __init__(self, data: MediaGalleryComponentPayload, state: Optional[ConnectionState]) -> None:
self.items: List[MediaGalleryItem] = MediaGalleryItem._from_gallery(data['items'], state) self.items: List[MediaGalleryItem] = MediaGalleryItem._from_gallery(data['items'], state)
self.id: Optional[int] = data.get('id')
@property @property
def type(self) -> Literal[ComponentType.media_gallery]: def type(self) -> Literal[ComponentType.media_gallery]:
return ComponentType.media_gallery return ComponentType.media_gallery
def to_dict(self) -> MediaGalleryComponentPayload: def to_dict(self) -> MediaGalleryComponentPayload:
return { payload: MediaGalleryComponentPayload = {
'type': self.type.value, 'type': self.type.value,
'items': [item.to_dict() for item in self.items], 'items': [item.to_dict() for item in self.items],
} }
if self.id is not None:
payload['id'] = self.id
return payload
class FileComponent(Component): class FileComponent(Component):
@ -1044,11 +1107,14 @@ class FileComponent(Component):
The unfurled attachment contents of the file. The unfurled attachment contents of the file.
spoiler: :class:`bool` spoiler: :class:`bool`
Whether this file is flagged as a spoiler. Whether this file is flagged as a spoiler.
id: Optional[:class:`int`]
The ID of this component.
""" """
__slots__ = ( __slots__ = (
'media', 'media',
'spoiler', 'spoiler',
'id',
) )
__repr_info__ = __slots__ __repr_info__ = __slots__
@ -1056,17 +1122,21 @@ class FileComponent(Component):
def __init__(self, data: FileComponentPayload, state: Optional[ConnectionState]) -> None: def __init__(self, data: FileComponentPayload, state: Optional[ConnectionState]) -> None:
self.media: UnfurledMediaItem = UnfurledMediaItem._from_data(data['file'], state) self.media: UnfurledMediaItem = UnfurledMediaItem._from_data(data['file'], state)
self.spoiler: bool = data.get('spoiler', False) self.spoiler: bool = data.get('spoiler', False)
self.id: Optional[int] = data.get('id')
@property @property
def type(self) -> Literal[ComponentType.file]: def type(self) -> Literal[ComponentType.file]:
return ComponentType.file return ComponentType.file
def to_dict(self) -> FileComponentPayload: def to_dict(self) -> FileComponentPayload:
return { payload: FileComponentPayload = {
'type': self.type.value, 'type': self.type.value,
'file': self.media.to_dict(), # type: ignore 'file': self.media.to_dict(), # type: ignore
'spoiler': self.spoiler, 'spoiler': self.spoiler,
} }
if self.id is not None:
payload['id'] = self.id
return payload
class SeparatorComponent(Component): class SeparatorComponent(Component):
@ -1087,11 +1157,14 @@ class SeparatorComponent(Component):
The spacing size of the separator. The spacing size of the separator.
visible: :class:`bool` visible: :class:`bool`
Whether this separator is visible and shows a divider. Whether this separator is visible and shows a divider.
id: Optional[:class:`int`]
The ID of this component.
""" """
__slots__ = ( __slots__ = (
'spacing', 'spacing',
'visible', 'visible',
'id',
) )
__repr_info__ = __slots__ __repr_info__ = __slots__
@ -1102,17 +1175,21 @@ class SeparatorComponent(Component):
) -> None: ) -> None:
self.spacing: SeparatorSize = try_enum(SeparatorSize, data.get('spacing', 1)) self.spacing: SeparatorSize = try_enum(SeparatorSize, data.get('spacing', 1))
self.visible: bool = data.get('divider', True) self.visible: bool = data.get('divider', True)
self.id: Optional[int] = data.get('id')
@property @property
def type(self) -> Literal[ComponentType.separator]: def type(self) -> Literal[ComponentType.separator]:
return ComponentType.separator return ComponentType.separator
def to_dict(self) -> SeparatorComponentPayload: def to_dict(self) -> SeparatorComponentPayload:
return { payload: SeparatorComponentPayload = {
'type': self.type.value, 'type': self.type.value,
'divider': self.visible, 'divider': self.visible,
'spacing': self.spacing.value, 'spacing': self.spacing.value,
} }
if self.id is not None:
payload['id'] = self.id
return payload
class Container(Component): class Container(Component):
@ -1133,10 +1210,13 @@ class Container(Component):
This container's children. This container's children.
spoiler: :class:`bool` spoiler: :class:`bool`
Whether this container is flagged as a spoiler. Whether this container is flagged as a spoiler.
id: Optional[:class:`int`]
The ID of this component.
""" """
def __init__(self, data: ContainerComponentPayload, state: Optional[ConnectionState]) -> None: def __init__(self, data: ContainerComponentPayload, state: Optional[ConnectionState]) -> None:
self.children: List[Component] = [] self.children: List[Component] = []
self.id: Optional[int] = data.get('id')
for child in data['components']: for child in data['components']:
comp = _component_factory(child, state) comp = _component_factory(child, state)
@ -1158,6 +1238,18 @@ class Container(Component):
accent_color = accent_colour accent_color = accent_colour
def to_dict(self) -> ContainerComponentPayload:
payload: ContainerComponentPayload = {
'type': self.type.value, # type: ignore
'spoiler': self.spoiler,
'components': [c.to_dict() for c in self.children],
}
if self.id is not None:
payload['id'] = self.id
if self._colour:
payload['accent_color'] = self._colour.value
return payload
def _component_factory(data: ComponentPayload, state: Optional[ConnectionState] = None) -> Optional[Component]: def _component_factory(data: ComponentPayload, state: Optional[ConnectionState] = None) -> Optional[Component]:
if data['type'] == 1: if data['type'] == 1:

5
discord/ui/action_row.py

@ -234,10 +234,13 @@ class ActionRow(Item[V]):
for item in self._children: for item in self._children:
components.append(item.to_component_dict()) components.append(item.to_component_dict())
return { base = {
'type': self.type.value, 'type': self.type.value,
'components': components, 'components': components,
} }
if self.id is not None:
base['id'] = self.id
return base
def button( def button(
self, self,

3
discord/ui/item.py

@ -127,8 +127,7 @@ class Item(Generic[V]):
@property @property
def id(self) -> Optional[int]: def id(self) -> Optional[int]:
"""Optional[:class:`int`]: The ID of this component. """Optional[:class:`int`]: The ID of this component."""
"""
return self._id return self._id
@id.setter @id.setter

Loading…
Cancel
Save