Skip to content

Commit 9af88cf

Browse files
committed
Merge remote-tracking branch 'origin/master' into feat/model3
# Conflicts: # CHANGELOG.md
2 parents f32b688 + d5d162a commit 9af88cf

File tree

19 files changed

+714
-57
lines changed

19 files changed

+714
-57
lines changed

CHANGELOG.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,14 @@ These changes are available on the `master` branch, but have not yet been releas
2020
- Added support for setting guild-specific `avatar`, `banner`, and `bio` for the bot
2121
user through `Member.edit`.
2222
([#2908](https://github.com/Pycord-Development/pycord/pull/2908))
23+
- Added support for select default values.
24+
([#2899](https://github.com/Pycord-Development/pycord/pull/2899))
25+
- Adds a new generic parameter to selects to type `ui.Select.values` return type.
26+
- Adds `SelectDefaultValue` object to create select default values.
27+
- Adds `SelectDefaultValueType` enum.
28+
- Adds pre-typed and pre-constructed with select_type `ui.Select` aliases for the
29+
different select types: `ui.StringSelect`, `ui.UserSelect`, `ui.RoleSelect`,
30+
`ui.MentionableSelect`, and `ui.ChannelSelect`.
2331

2432
### Changed
2533

@@ -35,6 +43,8 @@ These changes are available on the `master` branch, but have not yet been releas
3543
([#2916](https://github.com/Pycord-Development/pycord/pull/2916))
3644
- Fixed a crash when processing message edit events while message cache was disabled.
3745
([#2924](https://github.com/Pycord-Development/pycord/pull/2924))
46+
- Fixed OPUS Decode Error when recording audio.
47+
([#2925](https://github.com/Pycord-Development/pycord/pull/2925))
3848

3949
### Removed
4050

discord/abc.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -235,7 +235,7 @@ class User(Snowflake, Protocol):
235235
name: str
236236
discriminator: str
237237
global_name: str | None
238-
avatar: Asset
238+
avatar: Asset | None
239239
bot: bool
240240

241241
@property

discord/components.py

Lines changed: 186 additions & 2 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
@@ -34,6 +34,7 @@
3434
ChannelType,
3535
ComponentType,
3636
InputTextStyle,
37+
SelectDefaultValueType,
3738
SeparatorSpacingSize,
3839
try_enum,
3940
)
@@ -42,9 +43,9 @@
4243
from .utils import MISSING, find, get_slots
4344

4445
if TYPE_CHECKING:
46+
from . import abc
4547
from .emoji import AppEmoji, GuildEmoji
4648
from .types.components import ActionRow as ActionRowPayload
47-
from .types.components import BaseComponent as BaseComponentPayload
4849
from .types.components import ButtonComponent as ButtonComponentPayload
4950
from .types.components import Component as ComponentPayload
5051
from .types.components import ContainerComponent as ContainerComponentPayload
@@ -54,6 +55,7 @@
5455
from .types.components import MediaGalleryComponent as MediaGalleryComponentPayload
5556
from .types.components import MediaGalleryItem as MediaGalleryItemPayload
5657
from .types.components import SectionComponent as SectionComponentPayload
58+
from .types.components import SelectDefaultValue as SelectDefaultValuePayload
5759
from .types.components import SelectMenu as SelectMenuPayload
5860
from .types.components import SelectOption as SelectOptionPayload
5961
from .types.components import SeparatorComponent as SeparatorComponentPayload
@@ -79,6 +81,7 @@
7981
"Separator",
8082
"Container",
8183
"Label",
84+
"SelectDefaultValue",
8285
)
8386

8487
C = TypeVar("C", bound="Component")
@@ -438,6 +441,7 @@ class SelectMenu(Component):
438441
"channel_types",
439442
"disabled",
440443
"required",
444+
"default_values",
441445
)
442446

443447
__repr_info__: ClassVar[tuple[str, ...]] = __slots__
@@ -458,6 +462,9 @@ def __init__(self, data: SelectMenuPayload):
458462
try_enum(ChannelType, ct) for ct in data.get("channel_types", [])
459463
]
460464
self.required: bool | None = data.get("required")
465+
self.default_values: list[SelectDefaultValue] = SelectDefaultValue._from_data(
466+
data.get("default_values")
467+
)
461468

462469
def to_dict(self) -> SelectMenuPayload:
463470
payload: SelectMenuPayload = {
@@ -477,10 +484,187 @@ def to_dict(self) -> SelectMenuPayload:
477484
payload["placeholder"] = self.placeholder
478485
if self.required is not None:
479486
payload["required"] = self.required
487+
if self.type is not ComponentType.string_select:
488+
payload["default_values"] = [dv.to_dict() for dv in self.default_values]
480489

481490
return payload
482491

483492

493+
class SelectDefaultValue:
494+
r"""Represents a :class:`discord.SelectMenu`\s default value.
495+
496+
This is only applicable to selects of type other than :attr:`ComponentType.string_select`.
497+
498+
.. versionadded:: 2.7
499+
500+
Parameters
501+
----------
502+
object: :class:`abc.Snowflake`
503+
The model type this select default value is based of.
504+
505+
Below, is a table defining the model instance type and the default value type it will be mapped:
506+
507+
+-----------------------------------+--------------------------------------------------------------------------+
508+
| Model Type | Default Value Type |
509+
+-----------------------------------+--------------------------------------------------------------------------+
510+
| :class:`discord.User` | :attr:`discord.SelectDefaultValueType.user` |
511+
+-----------------------------------+--------------------------------------------------------------------------+
512+
| :class:`discord.Member` | :attr:`discord.SelectDefaultValueType.user` |
513+
+-----------------------------------+--------------------------------------------------------------------------+
514+
| :class:`discord.Role` | :attr:`discord.SelectDefaultValueType.role` |
515+
+-----------------------------------+--------------------------------------------------------------------------+
516+
| :class:`discord.abc.GuildChannel` | :attr:`discord.SelectDefaultValueType.channel` |
517+
+-----------------------------------+--------------------------------------------------------------------------+
518+
| :class:`discord.Object` | depending on :attr:`discord.Object.type`, it will be mapped to any above |
519+
+-----------------------------------+--------------------------------------------------------------------------+
520+
521+
If you pass a model that is not defined in the table, ``TypeError`` will be raised.
522+
523+
.. note::
524+
525+
The :class:`discord.abc.GuildChannel` protocol includes :class:`discord.TextChannel`, :class:`discord.VoiceChannel`, :class:`discord.StageChannel`,
526+
:class:`discord.ForumChannel`, :class:`discord.Thread`, :class:`discord.MediaChannel`. This list is not exhaustive, and is bound to change
527+
based of the new channel types Discord adds.
528+
529+
id: :class:`int`
530+
The ID of the default value. This cannot be used with ``object``.
531+
type: :class:`SelectDefaultValueType`
532+
The default value type. This cannot be used with ``object``.
533+
534+
Raises
535+
------
536+
TypeError
537+
You did not provide any parameter, you provided all parameters, or you provided ``id`` but not ``type``.
538+
"""
539+
540+
__slots__ = ("id", "type")
541+
542+
@overload
543+
def __init__(
544+
self,
545+
object: abc.Snowflake,
546+
/,
547+
) -> None: ...
548+
549+
@overload
550+
def __init__(
551+
self,
552+
/,
553+
*,
554+
id: int,
555+
type: SelectDefaultValueType,
556+
) -> None: ...
557+
558+
def __init__(
559+
self,
560+
object: abc.Snowflake = MISSING,
561+
/,
562+
*,
563+
id: int = MISSING,
564+
type: SelectDefaultValueType = MISSING,
565+
) -> None:
566+
self.id: int = id
567+
self.type: SelectDefaultValueType = type
568+
if object is not MISSING:
569+
if any(p is not MISSING for p in (id, type)):
570+
raise TypeError("you cannot pass id or type when passing object")
571+
self._handle_model(object, inst=self)
572+
elif id is not MISSING and type is not MISSING:
573+
self.id = id
574+
self.type = type
575+
else:
576+
raise TypeError("you must provide an object model, or an id and type")
577+
578+
def __repr__(self) -> str:
579+
return f"<SelectDefaultValue id={self.id} type={self.type}>"
580+
581+
@classmethod
582+
def _from_data(
583+
cls, default_values: list[SelectDefaultValuePayload] | None
584+
) -> list[SelectDefaultValue]:
585+
if not default_values:
586+
return []
587+
return [
588+
cls(id=int(d["id"]), type=try_enum(SelectDefaultValueType, d["type"]))
589+
for d in default_values
590+
]
591+
592+
@classmethod
593+
def _handle_model(
594+
cls,
595+
model: abc.Snowflake,
596+
select_type: ComponentType | None = None,
597+
inst: SelectDefaultValue | None = None,
598+
) -> SelectDefaultValue:
599+
# preventing >circular imports<
600+
from discord import Member, Object, Role, User, abc
601+
from discord.user import _UserTag
602+
603+
instances_mapping: dict[
604+
type, tuple[tuple[ComponentType, ...], SelectDefaultValueType]
605+
] = {
606+
Role: (
607+
(ComponentType.role_select, ComponentType.mentionable_select),
608+
SelectDefaultValueType.role,
609+
),
610+
User: (
611+
(ComponentType.user_select, ComponentType.mentionable_select),
612+
SelectDefaultValueType.user,
613+
),
614+
Member: (
615+
(ComponentType.user_select, ComponentType.mentionable_select),
616+
SelectDefaultValueType.user,
617+
),
618+
_UserTag: (
619+
(ComponentType.user_select, ComponentType.mentionable_select),
620+
SelectDefaultValueType.user,
621+
),
622+
abc.GuildChannel: (
623+
(ComponentType.channel_select,),
624+
SelectDefaultValueType.channel,
625+
),
626+
}
627+
628+
obj_id = model.id
629+
obj_type = model.__class__
630+
631+
if isinstance(model, Object):
632+
obj_type = model.type
633+
634+
sel_types = None
635+
def_type = None
636+
637+
for typ, (st, dt) in instances_mapping.items():
638+
if issubclass(obj_type, typ):
639+
sel_types = st
640+
def_type = dt
641+
break
642+
643+
if sel_types is None or def_type is None:
644+
raise TypeError(
645+
f"{obj_type.__name__} is not a valid instance for a select default value"
646+
)
647+
648+
# we can't actually check select types when not in a select context
649+
if select_type is not None and select_type not in sel_types:
650+
raise TypeError(
651+
f"{model.__class__.__name__} objects can not be set as a default value for {select_type.value} selects",
652+
)
653+
654+
if inst is None:
655+
return cls(id=obj_id, type=def_type)
656+
else:
657+
inst.id = obj_id
658+
inst.type = def_type
659+
return inst
660+
661+
def to_dict(self) -> SelectDefaultValuePayload:
662+
return {
663+
"id": self.id,
664+
"type": self.type.value,
665+
}
666+
667+
484668
class SelectOption:
485669
"""Represents a :class:`discord.SelectMenu`'s option.
486670

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

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

11231124

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

11261135

discord/object.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@
3333
if TYPE_CHECKING:
3434
import datetime
3535

36+
from .abc import Snowflake
37+
3638
SupportsIntCast = Union[SupportsInt, str, bytes, bytearray]
3739

3840
__all__ = ("Object",)
@@ -70,9 +72,11 @@ class Object(Hashable):
7072
----------
7173
id: :class:`int`
7274
The ID of the object.
75+
type: type[:class:`abc.Snowflake`]
76+
The model this object's ID is based off.
7377
"""
7478

75-
def __init__(self, id: SupportsIntCast):
79+
def __init__(self, id: SupportsIntCast, type: type[Snowflake] = utils.MISSING):
7680
try:
7781
id = int(id)
7882
except ValueError:
@@ -81,6 +85,7 @@ def __init__(self, id: SupportsIntCast):
8185
) from None
8286
else:
8387
self.id = id
88+
self.type: type[Snowflake] = type or self.__class__
8489

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

discord/role.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -402,7 +402,7 @@ def _update(self, data: RolePayload):
402402
self._permissions: int = int(data.get("permissions", 0))
403403
self.position: int = data.get("position", 0)
404404
self._colour: int = data.get("color", 0)
405-
self.colours: RoleColours | None = RoleColours._from_payload(data["colors"])
405+
self.colours: RoleColours = RoleColours._from_payload(data["colors"])
406406
self.hoist: bool = data.get("hoist", False)
407407
self.managed: bool = data.get("managed", False)
408408
self.mentionable: bool = data.get("mentionable", False)
@@ -574,8 +574,8 @@ async def edit(
574574
permissions: Permissions = MISSING,
575575
colour: Colour | int = MISSING,
576576
color: Colour | int = MISSING,
577-
colours: RoleColours | None = MISSING,
578-
colors: RoleColours | None = MISSING,
577+
colours: RoleColours = MISSING,
578+
colors: RoleColours = MISSING,
579579
holographic: bool = MISSING,
580580
hoist: bool = MISSING,
581581
mentionable: bool = MISSING,

0 commit comments

Comments
 (0)