Skip to content

Commit 929545e

Browse files
committed
comments
1 parent 77202d1 commit 929545e

File tree

2 files changed

+159
-53
lines changed

2 files changed

+159
-53
lines changed

discord/components.py

Lines changed: 122 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525

2626
from __future__ import annotations
2727

28-
from typing import TYPE_CHECKING, Any, ClassVar, Iterator, TypeVar
28+
from typing import TYPE_CHECKING, Any, ClassVar, Iterator, TypeVar, overload
2929

3030
from .asset import AssetMixin
3131
from .colour import Colour
@@ -43,6 +43,7 @@
4343
from .utils import MISSING, find, get_slots
4444

4545
if TYPE_CHECKING:
46+
from . import abc
4647
from .emoji import AppEmoji, GuildEmoji
4748
from .types.components import ActionRow as ActionRowPayload
4849
from .types.components import ButtonComponent as ButtonComponentPayload
@@ -497,21 +498,83 @@ class SelectDefaultValue:
497498
498499
Parameters
499500
----------
501+
object: :class:`abc.Snowflake`
502+
The model type this select default value is based of.
503+
504+
Below, is a table defining the model instance type and the default value type it will be mapped:
505+
506+
+-----------------------------------+--------------------------------------------------------------------------+
507+
| Model Type | Default Value Type |
508+
+-----------------------------------+--------------------------------------------------------------------------+
509+
| :class:`discord.User` | :attr:`discord.SelectDefaultValueType.user` |
510+
+-----------------------------------+--------------------------------------------------------------------------+
511+
| :class:`discord.Member` | :attr:`discord.SelectDefaultValueType.user` |
512+
+-----------------------------------+--------------------------------------------------------------------------+
513+
| :class:`discord.Role` | :attr:`discord.SelectDefaultValueType.role` |
514+
+-----------------------------------+--------------------------------------------------------------------------+
515+
| :class:`discord.abc.GuildChannel` | :attr:`discord.SelectDefaultValueType.channel` |
516+
+-----------------------------------+--------------------------------------------------------------------------+
517+
| :class:`discord.Object` | depending on :attr:`discord.Object.type`, it will be mapped to any above |
518+
+-----------------------------------+--------------------------------------------------------------------------+
519+
520+
If you pass a model that is not defined in the table, ``TypeError`` will be raised.
521+
522+
.. note::
523+
524+
The :class:`discord.abc.GuildChannel` protocol includes :class:`discord.TextChannel`, :class:`discord.VoiceChannel`, :class:`discord.StageChannel`,
525+
:class:`discord.ForumChannel`, :class:`discord.Thread`, :class:`discord.MediaChannel`. This list is not exhaustive, and is bound to change
526+
based of the new channel types Discord adds.
527+
500528
id: :class:`int`
501-
The ID of the default value.
529+
The ID of the default value. This cannot be used with ``object``.
502530
type: :class:`SelectDefaultValueType`
503-
The default value type.
531+
The default value type. This cannot be used with ``object``.
532+
533+
Raises
534+
------
535+
TypeError
536+
You did not provide any parameter, you provided all parameters, or you provided ``id`` but not ``type``.
504537
"""
505538

506539
__slots__ = ("id", "type")
507540

541+
@overload
508542
def __init__(
509543
self,
544+
object: abc.Snowflake,
545+
/,
546+
) -> None: ...
547+
548+
@overload
549+
def __init__(
550+
self,
551+
/,
552+
*,
510553
id: int,
511554
type: SelectDefaultValueType,
555+
) -> None: ...
556+
557+
def __init__(
558+
self,
559+
object: abc.Snowflake = MISSING,
560+
/,
561+
*,
562+
id: int = MISSING,
563+
type: SelectDefaultValueType = MISSING,
512564
) -> None:
513565
self.id: int = id
514566
self.type: SelectDefaultValueType = type
567+
if object is not MISSING:
568+
if any(p is not MISSING for p in (id, type)):
569+
raise TypeError("you cannot pass id or type when passing object")
570+
self._handle_model(object, inst=self)
571+
elif id is not MISSING and type is not MISSING:
572+
self.id = id
573+
self.type = type
574+
else:
575+
raise TypeError(
576+
"you must provide an object model, or an id and type"
577+
)
515578

516579
@classmethod
517580
def _from_data(
@@ -524,6 +587,62 @@ def _from_data(
524587
for d in default_values
525588
]
526589

590+
@classmethod
591+
def _handle_model(cls, model: abc.Snowflake, select_type: ComponentType | None = None, inst: SelectDefaultValue | None = None) -> SelectDefaultValue:
592+
# preventing >circular imports<
593+
from discord import abc, Role, User, Member, Object
594+
595+
instances_mapping: dict[
596+
type, tuple[tuple[ComponentType, ...], SelectDefaultValueType]
597+
] = {
598+
Role: (
599+
(ComponentType.role_select, ComponentType.mentionable_select),
600+
SelectDefaultValueType.role,
601+
),
602+
User: (
603+
(ComponentType.user_select, ComponentType.mentionable_select),
604+
SelectDefaultValueType.user,
605+
),
606+
Member: (
607+
(ComponentType.user_select, ComponentType.mentionable_select),
608+
SelectDefaultValueType.user,
609+
),
610+
abc.User: (
611+
(ComponentType.user_select, ComponentType.mentionable_select),
612+
SelectDefaultValueType.user,
613+
),
614+
abc.GuildChannel: (
615+
(ComponentType.channel_select,),
616+
SelectDefaultValueType.channel,
617+
),
618+
}
619+
620+
obj_id = model.id
621+
obj_type = model.__class__
622+
623+
if isinstance(model, Object):
624+
obj_type = model.type
625+
626+
try:
627+
sel_types, def_type = instances_mapping[obj_type]
628+
except KeyError:
629+
raise TypeError(
630+
f"{model.__class__.__name__} is not a valid instance for a select default value",
631+
)
632+
633+
# we can't actually check select types when not in a select context
634+
if select_type is not None and select_type not in sel_types:
635+
raise TypeError(
636+
f"{model.__class__.__name__} objects can not be set as a default value for {select_type.value} selects",
637+
)
638+
639+
if inst is None:
640+
return cls(id=obj_id, type=def_type)
641+
else:
642+
inst.id = obj_id
643+
inst.type = def_type
644+
return inst
645+
527646
def to_dict(self) -> SelectDefaultValuePayload:
528647
return {
529648
"id": self.id,

discord/ui/select.py

Lines changed: 37 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ class Select(Item[V]):
137137
default_values: Optional[Sequence[Union[:class:`discord.SelectDefaultValue`, :class:`discord.abc.Snowflake`]]]
138138
The default values of this select. Only applicable if :attr:`.select_type` is not :attr:`discord.ComponentType.string_select`.
139139
140-
This can be either :class:`discord.SelectDefaultValue` instances or models, which will be converted into :class:`discord.SelectDefaultvalue`
140+
These can be either :class:`discord.SelectDefaultValue` instances or models, which will be converted into :class:`discord.SelectDefaultValue`
141141
instances.
142142
143143
Below, is a table defining the model instance type and the default value type it will be mapped:
@@ -255,57 +255,11 @@ def _handle_default_values(
255255

256256
ret = []
257257

258-
from discord import abc # > circular import <
259-
260-
instances_mapping: dict[
261-
type, tuple[tuple[ComponentType, ...], SelectDefaultValueType]
262-
] = {
263-
Role: (
264-
(ComponentType.role_select, ComponentType.mentionable_select),
265-
SelectDefaultValueType.role,
266-
),
267-
User: (
268-
(ComponentType.user_select, ComponentType.mentionable_select),
269-
SelectDefaultValueType.user,
270-
),
271-
Member: (
272-
(ComponentType.user_select, ComponentType.mentionable_select),
273-
SelectDefaultValueType.user,
274-
),
275-
abc.User: (
276-
(ComponentType.user_select, ComponentType.mentionable_select),
277-
SelectDefaultValueType.user,
278-
),
279-
abc.GuildChannel: (
280-
(ComponentType.channel_select,),
281-
SelectDefaultValueType.channel,
282-
),
283-
}
284-
285258
for dv in default_values:
286259
if isinstance(dv, SelectDefaultValue):
287260
ret.append(dv)
288261
continue
289-
290-
obj_id = dv.id
291-
obj_type = dv.__class__
292-
293-
if isinstance(dv, Object):
294-
obj_type = dv.type
295-
296-
try:
297-
sel_type, def_type = instances_mapping[obj_type]
298-
except KeyError:
299-
raise TypeError(
300-
f"{dv.__class__.__name__} is not a valid instance for default_values"
301-
)
302-
303-
if select_type not in sel_type:
304-
raise TypeError(
305-
f"{dv.__class__.__name__} objects can not be set as a default value for {select_type.value} selects"
306-
)
307-
308-
ret.append(SelectDefaultValue(id=obj_id, type=def_type))
262+
ret.append(SelectDefaultValue._handle_model(dv, select_type))
309263

310264
return ret
311265

@@ -466,7 +420,7 @@ def add_default_value(
466420

467421
def append_default_value(
468422
self,
469-
value: SelectDefaultValue,
423+
value: SelectDefaultValue | Snowflake,
470424
/,
471425
) -> Self:
472426
"""Appends a default value to this select menu.
@@ -475,9 +429,36 @@ def append_default_value(
475429
476430
Parameters
477431
----------
478-
value: :class:`discord.SelectDefaultValue`
432+
value: Union[:class:`discord.SelectDefaultValue`, :class:`discord.abc.Snowflake`]
479433
The default value to append to this select.
480434
435+
These can be either :class:`discord.SelectDefaultValue` instances or models, which will be converted into :class:`discord.SelectDefaultvalue`
436+
instances.
437+
438+
Below, is a table defining the model instance type and the default value type it will be mapped:
439+
440+
+-----------------------------------+--------------------------------------------------------------------------+
441+
| Model Type | Default Value Type |
442+
+-----------------------------------+--------------------------------------------------------------------------+
443+
| :class:`discord.User` | :attr:`discord.SelectDefaultValueType.user` |
444+
+-----------------------------------+--------------------------------------------------------------------------+
445+
| :class:`discord.Member` | :attr:`discord.SelectDefaultValueType.user` |
446+
+-----------------------------------+--------------------------------------------------------------------------+
447+
| :class:`discord.Role` | :attr:`discord.SelectDefaultValueType.role` |
448+
+-----------------------------------+--------------------------------------------------------------------------+
449+
| :class:`discord.abc.GuildChannel` | :attr:`discord.SelectDefaultValueType.channel` |
450+
+-----------------------------------+--------------------------------------------------------------------------+
451+
| :class:`discord.Object` | depending on :attr:`discord.Object.type`, it will be mapped to any above |
452+
+-----------------------------------+--------------------------------------------------------------------------+
453+
454+
If you pass a model that is not defined in the table, ``TypeError`` will be raised.
455+
456+
.. note::
457+
458+
The :class:`discord.abc.GuildChannel` protocol includes :class:`discord.TextChannel`, :class:`discord.VoiceChannel`, :class:`discord.StageChannel`,
459+
:class:`discord.ForumChannel`, :class:`discord.Thread`, :class:`discord.MediaChannel`. This list is not exhaustive, and is bound to change
460+
based of the new channel types Discord adds.
461+
481462
Raises
482463
------
483464
TypeError
@@ -492,6 +473,12 @@ def append_default_value(
492473
if len(self.default_values) >= 25:
493474
raise ValueError("maximum number of default values exceeded (25)")
494475

476+
if not isinstance(value, SelectDefaultValue):
477+
value = SelectDefaultValue._handle_model(value)
478+
479+
if not isinstance(value, SelectDefaultValue):
480+
raise TypeError(f"expected a SelectDefaultValue object, got {value.__class__.__name__}")
481+
495482
self._underlying.default_values.append(value)
496483
return self
497484

0 commit comments

Comments
 (0)