25
25
26
26
from __future__ import annotations
27
27
28
- from typing import TYPE_CHECKING , Any , ClassVar , Iterator , TypeVar
28
+ from typing import TYPE_CHECKING , Any , ClassVar , Iterator , TypeVar , overload
29
29
30
30
from .asset import AssetMixin
31
31
from .colour import Colour
34
34
ChannelType ,
35
35
ComponentType ,
36
36
InputTextStyle ,
37
+ SelectDefaultValueType ,
37
38
SeparatorSpacingSize ,
38
39
try_enum ,
39
40
)
42
43
from .utils import MISSING , find , get_slots
43
44
44
45
if TYPE_CHECKING :
46
+ from . import abc
45
47
from .emoji import AppEmoji , GuildEmoji
46
48
from .types .components import ActionRow as ActionRowPayload
47
- from .types .components import BaseComponent as BaseComponentPayload
48
49
from .types .components import ButtonComponent as ButtonComponentPayload
49
50
from .types .components import Component as ComponentPayload
50
51
from .types .components import ContainerComponent as ContainerComponentPayload
54
55
from .types .components import MediaGalleryComponent as MediaGalleryComponentPayload
55
56
from .types .components import MediaGalleryItem as MediaGalleryItemPayload
56
57
from .types .components import SectionComponent as SectionComponentPayload
58
+ from .types .components import SelectDefaultValue as SelectDefaultValuePayload
57
59
from .types .components import SelectMenu as SelectMenuPayload
58
60
from .types .components import SelectOption as SelectOptionPayload
59
61
from .types .components import SeparatorComponent as SeparatorComponentPayload
78
80
"Separator" ,
79
81
"Container" ,
80
82
"Label" ,
83
+ "SelectDefaultValue" ,
81
84
)
82
85
83
86
C = TypeVar ("C" , bound = "Component" )
@@ -437,6 +440,7 @@ class SelectMenu(Component):
437
440
"channel_types" ,
438
441
"disabled" ,
439
442
"required" ,
443
+ "default_values" ,
440
444
)
441
445
442
446
__repr_info__ : ClassVar [tuple [str , ...]] = __slots__
@@ -457,6 +461,9 @@ def __init__(self, data: SelectMenuPayload):
457
461
try_enum (ChannelType , ct ) for ct in data .get ("channel_types" , [])
458
462
]
459
463
self .required : bool | None = data .get ("required" )
464
+ self .default_values : list [SelectDefaultValue ] = SelectDefaultValue ._from_data (
465
+ data .get ("default_values" )
466
+ )
460
467
461
468
def to_dict (self ) -> SelectMenuPayload :
462
469
payload : SelectMenuPayload = {
@@ -476,10 +483,187 @@ def to_dict(self) -> SelectMenuPayload:
476
483
payload ["placeholder" ] = self .placeholder
477
484
if self .required is not None :
478
485
payload ["required" ] = self .required
486
+ if self .type is not ComponentType .string_select :
487
+ payload ["default_values" ] = [dv .to_dict () for dv in self .default_values ]
479
488
480
489
return payload
481
490
482
491
492
+ class SelectDefaultValue :
493
+ r"""Represents a :class:`discord.SelectMenu`\s default value.
494
+
495
+ This is only applicable to selects of type other than :attr:`ComponentType.string_select`.
496
+
497
+ .. versionadded:: 2.7
498
+
499
+ Parameters
500
+ ----------
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
+
528
+ id: :class:`int`
529
+ The ID of the default value. This cannot be used with ``object``.
530
+ type: :class:`SelectDefaultValueType`
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``.
537
+ """
538
+
539
+ __slots__ = ("id" , "type" )
540
+
541
+ @overload
542
+ def __init__ (
543
+ self ,
544
+ object : abc .Snowflake ,
545
+ / ,
546
+ ) -> None : ...
547
+
548
+ @overload
549
+ def __init__ (
550
+ self ,
551
+ / ,
552
+ * ,
553
+ id : int ,
554
+ 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 ,
564
+ ) -> None :
565
+ self .id : int = id
566
+ 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 ("you must provide an object model, or an id and type" )
576
+
577
+ def __repr__ (self ) -> str :
578
+ return f"<SelectDefaultValue id={ self .id } type={ self .type } >"
579
+
580
+ @classmethod
581
+ def _from_data (
582
+ cls , default_values : list [SelectDefaultValuePayload ] | None
583
+ ) -> list [SelectDefaultValue ]:
584
+ if not default_values :
585
+ return []
586
+ return [
587
+ cls (id = int (d ["id" ]), type = try_enum (SelectDefaultValueType , d ["type" ]))
588
+ for d in default_values
589
+ ]
590
+
591
+ @classmethod
592
+ def _handle_model (
593
+ cls ,
594
+ model : abc .Snowflake ,
595
+ select_type : ComponentType | None = None ,
596
+ inst : SelectDefaultValue | None = None ,
597
+ ) -> SelectDefaultValue :
598
+ # preventing >circular imports<
599
+ from discord import Member , Object , Role , User , abc
600
+ from discord .user import _UserTag
601
+
602
+ instances_mapping : dict [
603
+ type , tuple [tuple [ComponentType , ...], SelectDefaultValueType ]
604
+ ] = {
605
+ Role : (
606
+ (ComponentType .role_select , ComponentType .mentionable_select ),
607
+ SelectDefaultValueType .role ,
608
+ ),
609
+ User : (
610
+ (ComponentType .user_select , ComponentType .mentionable_select ),
611
+ SelectDefaultValueType .user ,
612
+ ),
613
+ Member : (
614
+ (ComponentType .user_select , ComponentType .mentionable_select ),
615
+ SelectDefaultValueType .user ,
616
+ ),
617
+ _UserTag : (
618
+ (ComponentType .user_select , ComponentType .mentionable_select ),
619
+ SelectDefaultValueType .user ,
620
+ ),
621
+ abc .GuildChannel : (
622
+ (ComponentType .channel_select ,),
623
+ SelectDefaultValueType .channel ,
624
+ ),
625
+ }
626
+
627
+ obj_id = model .id
628
+ obj_type = model .__class__
629
+
630
+ if isinstance (model , Object ):
631
+ obj_type = model .type
632
+
633
+ sel_types = None
634
+ def_type = None
635
+
636
+ for typ , (st , dt ) in instances_mapping .items ():
637
+ if issubclass (obj_type , typ ):
638
+ sel_types = st
639
+ def_type = dt
640
+ break
641
+
642
+ if sel_types is None or def_type is None :
643
+ raise TypeError (
644
+ f"{ obj_type .__name__ } is not a valid instance for a select default value"
645
+ )
646
+
647
+ # we can't actually check select types when not in a select context
648
+ if select_type is not None and select_type not in sel_types :
649
+ raise TypeError (
650
+ f"{ model .__class__ .__name__ } objects can not be set as a default value for { select_type .value } selects" ,
651
+ )
652
+
653
+ if inst is None :
654
+ return cls (id = obj_id , type = def_type )
655
+ else :
656
+ inst .id = obj_id
657
+ inst .type = def_type
658
+ return inst
659
+
660
+ def to_dict (self ) -> SelectDefaultValuePayload :
661
+ return {
662
+ "id" : self .id ,
663
+ "type" : self .type .value ,
664
+ }
665
+
666
+
483
667
class SelectOption :
484
668
"""Represents a :class:`discord.SelectMenu`'s option.
485
669
0 commit comments