mirror of
https://github.com/Rapptz/discord.py.git
synced 2025-09-05 09:26:10 +00:00
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:
@ -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
|
||||
|
Reference in New Issue
Block a user