Add support for components V2

Co-authored-by: Michael H <michael@michaelhall.tech>
Co-authored-by: Soheab <33902984+Soheab@users.noreply.github.com>
Co-authored-by: owocado <24418520+owocado@users.noreply.github.com>
Co-authored-by: Jay3332 <40323796+jay3332@users.noreply.github.com>
Co-authored-by: Danny <1695103+Rapptz@users.noreply.github.com>
This commit is contained in:
DA344
2025-08-14 02:37:23 +02:00
committed by GitHub
parent 6ec2e5329b
commit 50caa3c82c
33 changed files with 4214 additions and 298 deletions

View File

@ -25,6 +25,7 @@ DEALINGS IN THE SOFTWARE.
from __future__ import annotations
from typing import (
Any,
Coroutine,
List,
Literal,
Optional,
@ -42,7 +43,7 @@ from contextvars import ContextVar
import inspect
import os
from .item import Item, ItemCallbackType
from .item import Item, I
from ..enums import ChannelType, ComponentType, SelectDefaultValueType
from ..partial_emoji import PartialEmoji
from ..emoji import Emoji
@ -72,7 +73,8 @@ __all__ = (
if TYPE_CHECKING:
from typing_extensions import TypeAlias, TypeGuard
from .view import View
from .view import BaseView
from .action_row import ActionRow
from ..types.components import SelectMenu as SelectMenuPayload
from ..types.interactions import SelectMessageComponentInteractionData
from ..app_commands import AppCommandChannel, AppCommandThread
@ -101,14 +103,17 @@ if TYPE_CHECKING:
Thread,
]
V = TypeVar('V', bound='View', covariant=True)
ItemCallbackType = Callable[['S', Interaction[Any], I], Coroutine[Any, Any, Any]]
S = TypeVar('S', bound='Union[BaseView, ActionRow]', covariant=True)
V = TypeVar('V', bound='BaseView', covariant=True)
BaseSelectT = TypeVar('BaseSelectT', bound='BaseSelect[Any]')
SelectT = TypeVar('SelectT', bound='Select[Any]')
UserSelectT = TypeVar('UserSelectT', bound='UserSelect[Any]')
RoleSelectT = TypeVar('RoleSelectT', bound='RoleSelect[Any]')
ChannelSelectT = TypeVar('ChannelSelectT', bound='ChannelSelect[Any]')
MentionableSelectT = TypeVar('MentionableSelectT', bound='MentionableSelect[Any]')
SelectCallbackDecorator: TypeAlias = Callable[[ItemCallbackType[V, BaseSelectT]], BaseSelectT]
SelectCallbackDecorator: TypeAlias = Callable[['ItemCallbackType[S, BaseSelectT]'], BaseSelectT]
DefaultSelectComponentTypes = Literal[
ComponentType.user_select,
ComponentType.role_select,
@ -216,6 +221,7 @@ class BaseSelect(Item[V]):
'min_values',
'max_values',
'disabled',
'id',
)
__component_attributes__: Tuple[str, ...] = (
'custom_id',
@ -223,6 +229,7 @@ class BaseSelect(Item[V]):
'min_values',
'max_values',
'disabled',
'id',
)
def __init__(
@ -238,6 +245,7 @@ class BaseSelect(Item[V]):
options: List[SelectOption] = MISSING,
channel_types: List[ChannelType] = MISSING,
default_values: Sequence[SelectDefaultValue] = MISSING,
id: Optional[int] = None,
) -> None:
super().__init__()
self._provided_custom_id = custom_id is not MISSING
@ -255,11 +263,21 @@ class BaseSelect(Item[V]):
channel_types=[] if channel_types is MISSING else channel_types,
options=[] if options is MISSING else options,
default_values=[] if default_values is MISSING else default_values,
id=id,
)
self.row = row
self._values: List[PossibleValue] = []
@property
def id(self) -> Optional[int]:
"""Optional[:class:`int`]: The ID of this select."""
return self._underlying.id
@id.setter
def id(self, value: Optional[int]) -> None:
self._underlying.id = value
@property
def values(self) -> List[PossibleValue]:
values = selected_values.get({})
@ -390,6 +408,14 @@ class Select(BaseSelect[V]):
like to control the relative positioning of the row then passing an index is advised.
For example, row=1 will show up before row=2. Defaults to ``None``, which is automatic
ordering. The row number must be between 0 and 4 (i.e. zero indexed).
.. note::
This parameter is ignored when used in a :class:`ActionRow` or v2 component.
id: Optional[:class:`int`]
The ID of the component. This must be unique across the view.
.. versionadded:: 2.6
"""
__component_attributes__ = BaseSelect.__component_attributes__ + ('options',)
@ -404,6 +430,7 @@ class Select(BaseSelect[V]):
options: List[SelectOption] = MISSING,
disabled: bool = False,
row: Optional[int] = None,
id: Optional[int] = None,
) -> None:
super().__init__(
self.type,
@ -414,6 +441,7 @@ class Select(BaseSelect[V]):
disabled=disabled,
options=options,
row=row,
id=id,
)
@property
@ -545,6 +573,14 @@ class UserSelect(BaseSelect[V]):
like to control the relative positioning of the row then passing an index is advised.
For example, row=1 will show up before row=2. Defaults to ``None``, which is automatic
ordering. The row number must be between 0 and 4 (i.e. zero indexed).
.. note::
This parameter is ignored when used in a :class:`ActionRow` or v2 component.
id: Optional[:class:`int`]
The ID of the component. This must be unique across the view.
.. versionadded:: 2.6
"""
__component_attributes__ = BaseSelect.__component_attributes__ + ('default_values',)
@ -559,6 +595,7 @@ class UserSelect(BaseSelect[V]):
disabled: bool = False,
row: Optional[int] = None,
default_values: Sequence[ValidDefaultValues] = MISSING,
id: Optional[int] = None,
) -> None:
super().__init__(
self.type,
@ -569,6 +606,7 @@ class UserSelect(BaseSelect[V]):
disabled=disabled,
row=row,
default_values=_handle_select_defaults(default_values, self.type),
id=id,
)
@property
@ -637,6 +675,14 @@ class RoleSelect(BaseSelect[V]):
like to control the relative positioning of the row then passing an index is advised.
For example, row=1 will show up before row=2. Defaults to ``None``, which is automatic
ordering. The row number must be between 0 and 4 (i.e. zero indexed).
.. note::
This parameter is ignored when used in a :class:`ActionRow` or v2 component.
id: Optional[:class:`int`]
The ID of the component. This must be unique across the view.
.. versionadded:: 2.6
"""
__component_attributes__ = BaseSelect.__component_attributes__ + ('default_values',)
@ -651,6 +697,7 @@ class RoleSelect(BaseSelect[V]):
disabled: bool = False,
row: Optional[int] = None,
default_values: Sequence[ValidDefaultValues] = MISSING,
id: Optional[int] = None,
) -> None:
super().__init__(
self.type,
@ -661,6 +708,7 @@ class RoleSelect(BaseSelect[V]):
disabled=disabled,
row=row,
default_values=_handle_select_defaults(default_values, self.type),
id=id,
)
@property
@ -725,6 +773,14 @@ class MentionableSelect(BaseSelect[V]):
like to control the relative positioning of the row then passing an index is advised.
For example, row=1 will show up before row=2. Defaults to ``None``, which is automatic
ordering. The row number must be between 0 and 4 (i.e. zero indexed).
.. note::
This parameter is ignored when used in a :class:`ActionRow` or v2 component.
id: Optional[:class:`int`]
The ID of the component. This must be unique across the view.
.. versionadded:: 2.6
"""
__component_attributes__ = BaseSelect.__component_attributes__ + ('default_values',)
@ -739,6 +795,7 @@ class MentionableSelect(BaseSelect[V]):
disabled: bool = False,
row: Optional[int] = None,
default_values: Sequence[ValidDefaultValues] = MISSING,
id: Optional[int] = None,
) -> None:
super().__init__(
self.type,
@ -749,6 +806,7 @@ class MentionableSelect(BaseSelect[V]):
disabled=disabled,
row=row,
default_values=_handle_select_defaults(default_values, self.type),
id=id,
)
@property
@ -819,6 +877,14 @@ class ChannelSelect(BaseSelect[V]):
like to control the relative positioning of the row then passing an index is advised.
For example, row=1 will show up before row=2. Defaults to ``None``, which is automatic
ordering. The row number must be between 0 and 4 (i.e. zero indexed).
.. note::
This parameter is ignored when used in a :class:`ActionRow` or v2 component.
id: Optional[:class:`int`]
The ID of the component. This must be unique across the view.
.. versionadded:: 2.6
"""
__component_attributes__ = BaseSelect.__component_attributes__ + (
@ -837,6 +903,7 @@ class ChannelSelect(BaseSelect[V]):
disabled: bool = False,
row: Optional[int] = None,
default_values: Sequence[ValidDefaultValues] = MISSING,
id: Optional[int] = None,
) -> None:
super().__init__(
self.type,
@ -848,6 +915,7 @@ class ChannelSelect(BaseSelect[V]):
row=row,
channel_types=channel_types,
default_values=_handle_select_defaults(default_values, self.type),
id=id,
)
@property
@ -899,7 +967,8 @@ def select(
max_values: int = ...,
disabled: bool = ...,
row: Optional[int] = ...,
) -> SelectCallbackDecorator[V, SelectT]:
id: Optional[int] = ...,
) -> SelectCallbackDecorator[S, SelectT]:
...
@ -916,7 +985,8 @@ def select(
disabled: bool = ...,
default_values: Sequence[ValidDefaultValues] = ...,
row: Optional[int] = ...,
) -> SelectCallbackDecorator[V, UserSelectT]:
id: Optional[int] = ...,
) -> SelectCallbackDecorator[S, UserSelectT]:
...
@ -933,7 +1003,8 @@ def select(
disabled: bool = ...,
default_values: Sequence[ValidDefaultValues] = ...,
row: Optional[int] = ...,
) -> SelectCallbackDecorator[V, RoleSelectT]:
id: Optional[int] = ...,
) -> SelectCallbackDecorator[S, RoleSelectT]:
...
@ -950,7 +1021,8 @@ def select(
disabled: bool = ...,
default_values: Sequence[ValidDefaultValues] = ...,
row: Optional[int] = ...,
) -> SelectCallbackDecorator[V, ChannelSelectT]:
id: Optional[int] = ...,
) -> SelectCallbackDecorator[S, ChannelSelectT]:
...
@ -967,7 +1039,8 @@ def select(
disabled: bool = ...,
default_values: Sequence[ValidDefaultValues] = ...,
row: Optional[int] = ...,
) -> SelectCallbackDecorator[V, MentionableSelectT]:
id: Optional[int] = ...,
) -> SelectCallbackDecorator[S, MentionableSelectT]:
...
@ -983,7 +1056,8 @@ def select(
disabled: bool = False,
default_values: Sequence[ValidDefaultValues] = MISSING,
row: Optional[int] = None,
) -> SelectCallbackDecorator[V, BaseSelectT]:
id: Optional[int] = None,
) -> SelectCallbackDecorator[S, BaseSelectT]:
"""A decorator that attaches a select menu to a component.
The function being decorated should have three parameters, ``self`` representing
@ -1041,6 +1115,10 @@ def select(
like to control the relative positioning of the row then passing an index is advised.
For example, row=1 will show up before row=2. Defaults to ``None``, which is automatic
ordering. The row number must be between 0 and 4 (i.e. zero indexed).
.. note::
This parameter is ignored when used in a :class:`ActionRow` or v2 component.
min_values: :class:`int`
The minimum number of items that must be chosen for this select menu.
Defaults to 1 and must be between 0 and 25.
@ -1062,9 +1140,13 @@ def select(
Number of items must be in range of ``min_values`` and ``max_values``.
.. versionadded:: 2.4
id: Optional[:class:`int`]
The ID of the component. This must be unique across the view.
.. versionadded:: 2.6
"""
def decorator(func: ItemCallbackType[V, BaseSelectT]) -> ItemCallbackType[V, BaseSelectT]:
def decorator(func: ItemCallbackType[S, BaseSelectT]) -> ItemCallbackType[S, BaseSelectT]:
if not inspect.iscoroutinefunction(func):
raise TypeError('select function must be a coroutine function')
callback_cls = getattr(cls, '__origin__', cls)
@ -1080,6 +1162,7 @@ def select(
'min_values': min_values,
'max_values': max_values,
'disabled': disabled,
'id': id,
}
if issubclass(callback_cls, Select):
func.__discord_ui_model_kwargs__['options'] = options