Skip to content

Commit ce5f50c

Browse files
committed
implement select default values
1 parent 0038661 commit ce5f50c

File tree

10 files changed

+314
-19
lines changed

10 files changed

+314
-19
lines changed

discord/components.py

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
ChannelType,
3535
ComponentType,
3636
InputTextStyle,
37+
SelectDefaultValueType,
3738
SeparatorSpacingSize,
3839
try_enum,
3940
)
@@ -44,7 +45,6 @@
4445
if TYPE_CHECKING:
4546
from .emoji import AppEmoji, GuildEmoji
4647
from .types.components import ActionRow as ActionRowPayload
47-
from .types.components import BaseComponent as BaseComponentPayload
4848
from .types.components import ButtonComponent as ButtonComponentPayload
4949
from .types.components import Component as ComponentPayload
5050
from .types.components import ContainerComponent as ContainerComponentPayload
@@ -60,6 +60,7 @@
6060
from .types.components import TextDisplayComponent as TextDisplayComponentPayload
6161
from .types.components import ThumbnailComponent as ThumbnailComponentPayload
6262
from .types.components import UnfurledMediaItem as UnfurledMediaItemPayload
63+
from .types.components import SelectDefaultValue as SelectDefaultValuePayload
6364

6465
__all__ = (
6566
"Component",
@@ -437,6 +438,7 @@ class SelectMenu(Component):
437438
"channel_types",
438439
"disabled",
439440
"required",
441+
"default_values",
440442
)
441443

442444
__repr_info__: ClassVar[tuple[str, ...]] = __slots__
@@ -457,6 +459,7 @@ def __init__(self, data: SelectMenuPayload):
457459
try_enum(ChannelType, ct) for ct in data.get("channel_types", [])
458460
]
459461
self.required: bool | None = data.get("required")
462+
self.default_values: list[SelectDefaultValue] = SelectDefaultValue._from_data(data.get("default_values"))
460463

461464
def to_dict(self) -> SelectMenuPayload:
462465
payload: SelectMenuPayload = {
@@ -476,10 +479,50 @@ def to_dict(self) -> SelectMenuPayload:
476479
payload["placeholder"] = self.placeholder
477480
if self.required is not None:
478481
payload["required"] = self.required
482+
if self.type is not ComponentType.string_select:
483+
payload["default_values"] = [dv.to_dict() for dv in self.default_values]
479484

480485
return payload
481486

482487

488+
class SelectDefaultValue:
489+
r"""Represents a :class:`discord.SelectMenu`\s default value.
490+
491+
This is only applicable to selects of type other than :attr:`ComponentType.string_select`.
492+
493+
.. versionadded:: 2.7
494+
495+
Parameters
496+
----------
497+
id: :class:`int`
498+
The ID of the default value.
499+
type: :class:`SelectDefaultValueType`
500+
The default value type.
501+
"""
502+
503+
__slots__ = ("id", "type")
504+
505+
def __init__(
506+
self,
507+
id: int,
508+
type: SelectDefaultValueType,
509+
) -> None:
510+
self.id: int = id
511+
self.type: SelectDefaultValueType = type
512+
513+
@classmethod
514+
def _from_data(cls, default_values: list[SelectDefaultValuePayload] | None) -> list[SelectDefaultValue]:
515+
if not default_values:
516+
return []
517+
return [cls(id=int(d['id']), type=try_enum(SelectDefaultValueType, d['type'])) for d in default_values]
518+
519+
def to_dict(self) -> SelectDefaultValuePayload:
520+
return {
521+
"id": self.id,
522+
"type": self.type.value,
523+
}
524+
525+
483526
class SelectOption:
484527
"""Represents a :class:`discord.SelectMenu`'s option.
485528

discord/enums.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@
8383
"ThreadArchiveDuration",
8484
"SubscriptionStatus",
8585
"SeparatorSpacingSize",
86+
"SelectDefaultValueType",
8687
)
8788

8889

@@ -1120,6 +1121,14 @@ def __int__(self):
11201121
return self.value
11211122

11221123

1124+
class SelectDefaultValueType(Enum):
1125+
"""Represents the default value type of a select menu."""
1126+
1127+
channel = "channel"
1128+
role = "role"
1129+
user = "user"
1130+
1131+
11231132
T = TypeVar("T")
11241133

11251134

discord/object.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
from typing import TYPE_CHECKING, SupportsInt, Union
2929

3030
from . import utils
31+
from .abc import Snowflake
3132
from .mixins import Hashable
3233

3334
if TYPE_CHECKING:
@@ -70,9 +71,11 @@ class Object(Hashable):
7071
----------
7172
id: :class:`int`
7273
The ID of the object.
74+
type: type[:class:`abc.Snowflake`]
75+
The model this object's ID is based off.
7376
"""
7477

75-
def __init__(self, id: SupportsIntCast):
78+
def __init__(self, id: SupportsIntCast, type: type[Snowflake] = utils.MISSING):
7679
try:
7780
id = int(id)
7881
except ValueError:
@@ -81,6 +84,7 @@ def __init__(self, id: SupportsIntCast):
8184
) from None
8285
else:
8386
self.id = id
87+
self.type: type[Snowflake] = type or self.__class__
8488

8589
def __repr__(self) -> str:
8690
return f"<Object id={self.id!r}>"

discord/types/components.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
ButtonStyle = Literal[1, 2, 3, 4, 5, 6]
3838
InputTextStyle = Literal[1, 2]
3939
SeparatorSpacingSize = Literal[1, 2]
40+
SelectDefaultValueType = Literal['channel', 'role', 'user']
4041

4142

4243
class BaseComponent(TypedDict):
@@ -46,7 +47,7 @@ class BaseComponent(TypedDict):
4647

4748
class ActionRow(BaseComponent):
4849
type: Literal[1]
49-
components: list[ButtonComponent, InputText, SelectMenu]
50+
components: list[ButtonComponent | InputText | SelectMenu]
5051

5152

5253
class ButtonComponent(BaseComponent):
@@ -80,6 +81,11 @@ class SelectOption(TypedDict):
8081
default: bool
8182

8283

84+
class SelectDefaultValue(TypedDict):
85+
id: Snowflake
86+
type: SelectDefaultValueType
87+
88+
8389
class SelectMenu(BaseComponent):
8490
placeholder: NotRequired[str]
8591
min_values: NotRequired[int]
@@ -90,6 +96,7 @@ class SelectMenu(BaseComponent):
9096
type: Literal[3, 5, 6, 7, 8]
9197
custom_id: str
9298
required: NotRequired[bool]
99+
default_values: NotRequired[list[SelectDefaultValue]]
93100

94101

95102
class TextDisplayComponent(BaseComponent):
@@ -100,7 +107,7 @@ class TextDisplayComponent(BaseComponent):
100107
class SectionComponent(BaseComponent):
101108
type: Literal[9]
102109
components: list[TextDisplayComponent]
103-
accessory: NotRequired[ThumbnailComponent, ButtonComponent]
110+
accessory: NotRequired[ThumbnailComponent | ButtonComponent]
104111

105112

106113
class UnfurledMediaItem(TypedDict):

discord/ui/button.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -294,7 +294,7 @@ def button(
294294
emoji: str | GuildEmoji | AppEmoji | PartialEmoji | None = None,
295295
row: int | None = None,
296296
id: int | None = None,
297-
) -> Callable[[ItemCallbackType], ItemCallbackType]:
297+
) -> Callable[[ItemCallbackType[Button[V]]], Button[V]]:
298298
"""A decorator that attaches a button to a component.
299299
300300
The function being decorated should have three parameters, ``self`` representing
@@ -347,4 +347,4 @@ def decorator(func: ItemCallbackType) -> ItemCallbackType:
347347
}
348348
return func
349349

350-
return decorator
350+
return decorator # type: ignore # lie to the type checkers, because after a View is instated, the button callback is converted into a Button instance

0 commit comments

Comments
 (0)