Skip to content

Commit 78ab162

Browse files
authored
feat: add support select menu defaults (#1556)
* feat: add support select menu defaults * feat: add new objects to local scope __all__ * fix: use discordobject as base for dfaultselectvalue
1 parent 0cea688 commit 78ab162

File tree

1 file changed

+139
-5
lines changed

1 file changed

+139
-5
lines changed

interactions/models/discord/components.py

Lines changed: 139 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,22 @@
11
import contextlib
22
import uuid
33
from abc import abstractmethod
4-
from typing import Any, Dict, Iterator, List, Optional, Union
4+
from typing import Any, Dict, Iterator, List, Optional, Union, TYPE_CHECKING
55

6+
import attrs
67
import discord_typings
78

9+
import interactions.models.discord as d_models
10+
from interactions.models.discord.snowflake import Snowflake
811
from interactions.client.const import ACTION_ROW_MAX_ITEMS, MISSING
912
from interactions.client.mixins.serialization import DictSerializationMixin
13+
from interactions.models.discord.base import DiscordObject
1014
from interactions.models.discord.emoji import PartialEmoji, process_emoji
1115
from interactions.models.discord.enums import ButtonStyle, ChannelType, ComponentType
1216

17+
if TYPE_CHECKING:
18+
import interactions.models.discord
19+
1320
__all__ = (
1421
"BaseComponent",
1522
"InteractiveComponent",
@@ -26,6 +33,8 @@
2633
"spread_to_rows",
2734
"get_components_ids",
2835
"TYPE_COMPONENT_MAPPING",
36+
"SelectDefaultValues",
37+
"DefaultableSelectMenu",
2938
)
3039

3140

@@ -325,6 +334,87 @@ def to_dict(self) -> discord_typings.SelectMenuComponentData:
325334
}
326335

327336

337+
@attrs.define(eq=False, order=False, hash=False, slots=False)
338+
class SelectDefaultValues(DiscordObject):
339+
id: Snowflake
340+
"""ID of a user, role, or channel"""
341+
type: str
342+
"""Type of value that id represents. Either "user", "role", or "channel"""
343+
344+
@classmethod
345+
def from_object(cls, obj: DiscordObject) -> "SelectDefaultValues":
346+
"""Create a default value from a discord object."""
347+
match obj:
348+
case d_models.User():
349+
return cls(id=obj.id, type="user")
350+
case d_models.Member():
351+
return cls(id=obj.id, type="user")
352+
case d_models.BaseChannel():
353+
return cls(id=obj.id, type="channel")
354+
case d_models.Role():
355+
return cls(id=obj.id, type="role")
356+
case _:
357+
raise TypeError(
358+
f"Cannot convert {obj} of type {type(obj)} to a SelectDefaultValues - Expected User, Channel, Member, or Role"
359+
)
360+
361+
362+
class DefaultableSelectMenu(BaseSelectMenu):
363+
default_values: list[
364+
Union[
365+
"interactions.models.discord.BaseUser",
366+
"interactions.models.discord.Role",
367+
"interactions.models.discord.BaseChannel",
368+
"interactions.models.discord.Member",
369+
SelectDefaultValues,
370+
]
371+
] | None = None
372+
373+
def __init__(
374+
self,
375+
defaults: list[
376+
Union[
377+
"interactions.models.discord.BaseUser",
378+
"interactions.models.discord.Role",
379+
"interactions.models.discord.BaseChannel",
380+
"interactions.models.discord.Member",
381+
SelectDefaultValues,
382+
]
383+
]
384+
| None = None,
385+
**kwargs,
386+
) -> None:
387+
super().__init__(**kwargs)
388+
self.default_values = defaults
389+
390+
def add_default_value(
391+
self,
392+
value: Union[
393+
"interactions.models.discord.BaseUser",
394+
"interactions.models.discord.Role",
395+
"interactions.models.discord.BaseChannel",
396+
"interactions.models.discord.Member",
397+
SelectDefaultValues,
398+
],
399+
) -> None:
400+
if self.default_values is None:
401+
self.default_values = []
402+
self.default_values.append(value)
403+
404+
def to_dict(self) -> discord_typings.SelectMenuComponentData:
405+
data = super().to_dict()
406+
if self.default_values is not None:
407+
data["default_values"] = [ # type: ignore # waiting on discord typings to update
408+
value.to_dict()
409+
if isinstance(value, SelectDefaultValues)
410+
else SelectDefaultValues.from_object(value).to_dict()
411+
for value in self.default_values
412+
]
413+
414+
# Discord handles the type checking, no need to do it here
415+
return data
416+
417+
328418
class StringSelectOption(BaseComponent):
329419
"""
330420
Represents a select option.
@@ -461,7 +551,7 @@ def to_dict(self) -> discord_typings.SelectMenuComponentData:
461551
}
462552

463553

464-
class UserSelectMenu(BaseSelectMenu):
554+
class UserSelectMenu(DefaultableSelectMenu):
465555
"""
466556
Represents a user select component.
467557
@@ -481,6 +571,16 @@ def __init__(
481571
min_values: int = 1,
482572
max_values: int = 1,
483573
custom_id: str | None = None,
574+
default_values: list[
575+
Union[
576+
"interactions.models.discord.BaseUser",
577+
"interactions.models.discord.Role",
578+
"interactions.models.discord.BaseChannel",
579+
"interactions.models.discord.Member",
580+
SelectDefaultValues,
581+
],
582+
]
583+
| None = None,
484584
disabled: bool = False,
485585
) -> None:
486586
super().__init__(
@@ -489,12 +589,13 @@ def __init__(
489589
max_values=max_values,
490590
custom_id=custom_id,
491591
disabled=disabled,
592+
defaults=default_values,
492593
)
493594

494595
self.type: ComponentType = ComponentType.USER_SELECT
495596

496597

497-
class RoleSelectMenu(BaseSelectMenu):
598+
class RoleSelectMenu(DefaultableSelectMenu):
498599
"""
499600
Represents a user select component.
500601
@@ -515,19 +616,30 @@ def __init__(
515616
max_values: int = 1,
516617
custom_id: str | None = None,
517618
disabled: bool = False,
619+
default_values: list[
620+
Union[
621+
"interactions.models.discord.BaseUser",
622+
"interactions.models.discord.Role",
623+
"interactions.models.discord.BaseChannel",
624+
"interactions.models.discord.Member",
625+
SelectDefaultValues,
626+
],
627+
]
628+
| None = None,
518629
) -> None:
519630
super().__init__(
520631
placeholder=placeholder,
521632
min_values=min_values,
522633
max_values=max_values,
523634
custom_id=custom_id,
524635
disabled=disabled,
636+
defaults=default_values,
525637
)
526638

527639
self.type: ComponentType = ComponentType.ROLE_SELECT
528640

529641

530-
class MentionableSelectMenu(BaseSelectMenu):
642+
class MentionableSelectMenu(DefaultableSelectMenu):
531643
def __init__(
532644
self,
533645
*,
@@ -536,19 +648,30 @@ def __init__(
536648
max_values: int = 1,
537649
custom_id: str | None = None,
538650
disabled: bool = False,
651+
default_values: list[
652+
Union[
653+
"interactions.models.discord.BaseUser",
654+
"interactions.models.discord.Role",
655+
"interactions.models.discord.BaseChannel",
656+
"interactions.models.discord.Member",
657+
SelectDefaultValues,
658+
],
659+
]
660+
| None = None,
539661
) -> None:
540662
super().__init__(
541663
placeholder=placeholder,
542664
min_values=min_values,
543665
max_values=max_values,
544666
custom_id=custom_id,
545667
disabled=disabled,
668+
defaults=default_values,
546669
)
547670

548671
self.type: ComponentType = ComponentType.MENTIONABLE_SELECT
549672

550673

551-
class ChannelSelectMenu(BaseSelectMenu):
674+
class ChannelSelectMenu(DefaultableSelectMenu):
552675
def __init__(
553676
self,
554677
*,
@@ -558,13 +681,24 @@ def __init__(
558681
max_values: int = 1,
559682
custom_id: str | None = None,
560683
disabled: bool = False,
684+
default_values: list[
685+
Union[
686+
"interactions.models.discord.BaseUser",
687+
"interactions.models.discord.Role",
688+
"interactions.models.discord.BaseChannel",
689+
"interactions.models.discord.Member",
690+
SelectDefaultValues,
691+
],
692+
]
693+
| None = None,
561694
) -> None:
562695
super().__init__(
563696
placeholder=placeholder,
564697
min_values=min_values,
565698
max_values=max_values,
566699
custom_id=custom_id,
567700
disabled=disabled,
701+
defaults=default_values,
568702
)
569703

570704
self.channel_types: list[ChannelType] | None = channel_types or []

0 commit comments

Comments
 (0)