1
1
import contextlib
2
2
import uuid
3
3
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
5
5
6
+ import attrs
6
7
import discord_typings
7
8
9
+ import interactions .models .discord as d_models
10
+ from interactions .models .discord .snowflake import Snowflake
8
11
from interactions .client .const import ACTION_ROW_MAX_ITEMS , MISSING
9
12
from interactions .client .mixins .serialization import DictSerializationMixin
13
+ from interactions .models .discord .base import DiscordObject
10
14
from interactions .models .discord .emoji import PartialEmoji , process_emoji
11
15
from interactions .models .discord .enums import ButtonStyle , ChannelType , ComponentType
12
16
17
+ if TYPE_CHECKING :
18
+ import interactions .models .discord
19
+
13
20
__all__ = (
14
21
"BaseComponent" ,
15
22
"InteractiveComponent" ,
26
33
"spread_to_rows" ,
27
34
"get_components_ids" ,
28
35
"TYPE_COMPONENT_MAPPING" ,
36
+ "SelectDefaultValues" ,
37
+ "DefaultableSelectMenu" ,
29
38
)
30
39
31
40
@@ -325,6 +334,87 @@ def to_dict(self) -> discord_typings.SelectMenuComponentData:
325
334
}
326
335
327
336
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
+
328
418
class StringSelectOption (BaseComponent ):
329
419
"""
330
420
Represents a select option.
@@ -461,7 +551,7 @@ def to_dict(self) -> discord_typings.SelectMenuComponentData:
461
551
}
462
552
463
553
464
- class UserSelectMenu (BaseSelectMenu ):
554
+ class UserSelectMenu (DefaultableSelectMenu ):
465
555
"""
466
556
Represents a user select component.
467
557
@@ -481,6 +571,16 @@ def __init__(
481
571
min_values : int = 1 ,
482
572
max_values : int = 1 ,
483
573
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 ,
484
584
disabled : bool = False ,
485
585
) -> None :
486
586
super ().__init__ (
@@ -489,12 +589,13 @@ def __init__(
489
589
max_values = max_values ,
490
590
custom_id = custom_id ,
491
591
disabled = disabled ,
592
+ defaults = default_values ,
492
593
)
493
594
494
595
self .type : ComponentType = ComponentType .USER_SELECT
495
596
496
597
497
- class RoleSelectMenu (BaseSelectMenu ):
598
+ class RoleSelectMenu (DefaultableSelectMenu ):
498
599
"""
499
600
Represents a user select component.
500
601
@@ -515,19 +616,30 @@ def __init__(
515
616
max_values : int = 1 ,
516
617
custom_id : str | None = None ,
517
618
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 ,
518
629
) -> None :
519
630
super ().__init__ (
520
631
placeholder = placeholder ,
521
632
min_values = min_values ,
522
633
max_values = max_values ,
523
634
custom_id = custom_id ,
524
635
disabled = disabled ,
636
+ defaults = default_values ,
525
637
)
526
638
527
639
self .type : ComponentType = ComponentType .ROLE_SELECT
528
640
529
641
530
- class MentionableSelectMenu (BaseSelectMenu ):
642
+ class MentionableSelectMenu (DefaultableSelectMenu ):
531
643
def __init__ (
532
644
self ,
533
645
* ,
@@ -536,19 +648,30 @@ def __init__(
536
648
max_values : int = 1 ,
537
649
custom_id : str | None = None ,
538
650
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 ,
539
661
) -> None :
540
662
super ().__init__ (
541
663
placeholder = placeholder ,
542
664
min_values = min_values ,
543
665
max_values = max_values ,
544
666
custom_id = custom_id ,
545
667
disabled = disabled ,
668
+ defaults = default_values ,
546
669
)
547
670
548
671
self .type : ComponentType = ComponentType .MENTIONABLE_SELECT
549
672
550
673
551
- class ChannelSelectMenu (BaseSelectMenu ):
674
+ class ChannelSelectMenu (DefaultableSelectMenu ):
552
675
def __init__ (
553
676
self ,
554
677
* ,
@@ -558,13 +681,24 @@ def __init__(
558
681
max_values : int = 1 ,
559
682
custom_id : str | None = None ,
560
683
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 ,
561
694
) -> None :
562
695
super ().__init__ (
563
696
placeholder = placeholder ,
564
697
min_values = min_values ,
565
698
max_values = max_values ,
566
699
custom_id = custom_id ,
567
700
disabled = disabled ,
701
+ defaults = default_values ,
568
702
)
569
703
570
704
self .channel_types : list [ChannelType ] | None = channel_types or []
0 commit comments