Skip to content

Commit

Permalink
Merge branch 'master' into feat/poll_msg
Browse files Browse the repository at this point in the history
  • Loading branch information
Snipy7374 authored Nov 21, 2024
2 parents 894c686 + ac5a936 commit c7f9738
Show file tree
Hide file tree
Showing 39 changed files with 931 additions and 118 deletions.
1 change: 1 addition & 0 deletions changelog/1115.feature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add :class:`SelectDefaultValue`, and add :attr:`~UserSelectMenu.default_values` to all auto-populated select menu types.
1 change: 0 additions & 1 deletion changelog/1180.doc.rst

This file was deleted.

1 change: 1 addition & 0 deletions changelog/1184.feature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add the possibility to pass :class:`disnake.File` objects to :meth:`Embed.set_author` and :meth:`~Embed.set_footer`.
1 change: 1 addition & 0 deletions changelog/1203.feature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Implement new :attr:`.Member.guild_banner` property.
4 changes: 4 additions & 0 deletions changelog/993.feature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Support voice channel effect events.
- New events: :func:`on_voice_channel_effect`, :func:`on_raw_voice_channel_effect`.
- New types: :class:`VoiceChannelEffect`, :class:`RawVoiceChannelEffectEvent`.
- New enum: :class:`VoiceChannelEffectAnimationType`.
8 changes: 3 additions & 5 deletions disnake/abc.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@
from .permissions import PermissionOverwrite, Permissions
from .role import Role
from .sticker import GuildSticker, StandardSticker, StickerItem
from .ui.action_row import components_to_dict
from .utils import _overload_with_permissions
from .voice_client import VoiceClient, VoiceProtocol

Expand Down Expand Up @@ -179,6 +178,7 @@ def avatar(self) -> Optional[Asset]:
raise NotImplementedError


# FIXME: this shouldn't be a protocol. isinstance(thread, PrivateChannel) returns true, and issubclass doesn't work.
@runtime_checkable
class PrivateChannel(Snowflake, Protocol):
"""An ABC that details the common operations on a private Discord channel.
Expand Down Expand Up @@ -1719,16 +1719,14 @@ async def send(

if view is not None and components is not None:
raise TypeError("cannot pass both view and components parameter to send()")

elif view:
if not hasattr(view, "__discord_ui_view__"):
raise TypeError(f"view parameter must be View not {view.__class__!r}")

components_payload = view.to_components()

elif components:
components_payload = components_to_dict(components)
from .ui.action_row import components_to_dict

components_payload = components_to_dict(components)
else:
components_payload = None

Expand Down
13 changes: 13 additions & 0 deletions disnake/asset.py
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,19 @@ def _from_guild_avatar(
animated=animated,
)

@classmethod
def _from_guild_banner(
cls, state: AnyState, guild_id: int, member_id: int, banner: str
) -> Self:
animated = banner.startswith("a_")
format = "gif" if animated else "png"
return cls(
state,
url=f"{cls.BASE}/guilds/{guild_id}/users/{member_id}/banners/{banner}.{format}?size=1024",
key=banner,
animated=animated,
)

@classmethod
def _from_icon(cls, state: AnyState, object_id: int, icon_hash: str, path: str) -> Self:
return cls(
Expand Down
49 changes: 49 additions & 0 deletions disnake/channel.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
ThreadLayout,
ThreadSortOrder,
VideoQualityMode,
VoiceChannelEffectAnimationType,
try_enum,
try_enum_to_int,
)
Expand All @@ -50,6 +51,7 @@
from .utils import MISSING

__all__ = (
"VoiceChannelEffect",
"TextChannel",
"VoiceChannel",
"StageChannel",
Expand Down Expand Up @@ -90,13 +92,59 @@
)
from .types.snowflake import SnowflakeList
from .types.threads import ThreadArchiveDurationLiteral
from .types.voice import VoiceChannelEffect as VoiceChannelEffectPayload
from .ui.action_row import Components, MessageUIComponent
from .ui.view import View
from .user import BaseUser, ClientUser, User
from .voice_region import VoiceRegion
from .webhook import Webhook


class VoiceChannelEffect:
"""An effect sent by a member in a voice channel.
Different sets of attributes will be present, depending on the type of effect.
.. versionadded:: 2.10
Attributes
----------
emoji: Optional[Union[:class:`Emoji`, :class:`PartialEmoji`]]
The emoji, for emoji reaction effects.
animation_type: Optional[:class:`VoiceChannelEffectAnimationType`]
The emoji animation type, for emoji reaction effects.
animation_id: Optional[:class:`int`]
The emoji animation ID, for emoji reaction effects.
"""

__slots__ = (
"emoji",
"animation_type",
"animation_id",
)

def __init__(self, *, data: VoiceChannelEffectPayload, state: ConnectionState) -> None:
self.emoji: Optional[Union[Emoji, PartialEmoji]] = None
if emoji_data := data.get("emoji"):
emoji = state._get_emoji_from_data(emoji_data)
if isinstance(emoji, str):
emoji = PartialEmoji(name=emoji)
self.emoji = emoji

self.animation_type = (
try_enum(VoiceChannelEffectAnimationType, value)
if (value := data.get("animation_type")) is not None
else None
)
self.animation_id: Optional[int] = utils._get_as_snowflake(data, "animation_id")

def __repr__(self) -> str:
return (
f"<VoiceChannelEffect emoji={self.emoji!r} animation_type={self.animation_type!r}"
f" animation_id={self.animation_id!r}>"
)


async def _single_delete_strategy(messages: Iterable[Message]) -> None:
for m in messages:
await m.delete()
Expand Down Expand Up @@ -5044,6 +5092,7 @@ def _channel_type_factory(
cls: Union[Type[disnake.abc.GuildChannel], Type[Thread]]
) -> List[ChannelType]:
return {
# FIXME: this includes private channels; improve this once there's a common base type for all channels
disnake.abc.GuildChannel: list(ChannelType.__members__.values()),
VocalGuildChannel: [ChannelType.voice, ChannelType.stage_voice],
disnake.abc.PrivateChannel: [ChannelType.private, ChannelType.group],
Expand Down
7 changes: 6 additions & 1 deletion disnake/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -1272,7 +1272,12 @@ def run(self, *args: Any, **kwargs: Any) -> None:
This function must be the last function to call due to the fact that it
is blocking. That means that registration of events or anything being
called after this function call will not execute until it returns.
called after this function call will not execute until it returns
Parameters
----------
token: :class:`str`
The discord token of the bot that is being ran.
"""
loop = self.loop

Expand Down
83 changes: 81 additions & 2 deletions disnake/components.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,14 @@
cast,
)

from .enums import ButtonStyle, ChannelType, ComponentType, TextInputStyle, try_enum
from .enums import (
ButtonStyle,
ChannelType,
ComponentType,
SelectDefaultValueType,
TextInputStyle,
try_enum,
)
from .partial_emoji import PartialEmoji, _EmojiTag
from .utils import MISSING, assert_never, get_slots

Expand All @@ -35,6 +42,7 @@
Component as ComponentPayload,
MentionableSelectMenu as MentionableSelectMenuPayload,
RoleSelectMenu as RoleSelectMenuPayload,
SelectDefaultValue as SelectDefaultValuePayload,
SelectOption as SelectOptionPayload,
StringSelectMenu as StringSelectMenuPayload,
TextInput as TextInputPayload,
Expand All @@ -53,6 +61,7 @@
"MentionableSelectMenu",
"ChannelSelectMenu",
"SelectOption",
"SelectDefaultValue",
"TextInput",
)

Expand Down Expand Up @@ -264,6 +273,12 @@ class BaseSelectMenu(Component):
A list of options that can be selected in this select menu.
disabled: :class:`bool`
Whether the select menu is disabled or not.
default_values: List[:class:`SelectDefaultValue`]
The list of values (users/roles/channels) that are selected by default.
If set, the number of items must be within the bounds set by ``min_values`` and ``max_values``.
Only available for auto-populated select menus.
.. versionadded:: 2.10
"""

__slots__: Tuple[str, ...] = (
Expand All @@ -272,9 +287,11 @@ class BaseSelectMenu(Component):
"min_values",
"max_values",
"disabled",
"default_values",
)

__repr_info__: ClassVar[Tuple[str, ...]] = __slots__
# FIXME: this isn't pretty; we should decouple __repr__ from slots
__repr_info__: ClassVar[Tuple[str, ...]] = tuple(s for s in __slots__ if s != "default_values")

# n.b: ideally this would be `BaseSelectMenuPayload`,
# but pyright made TypedDict keys invariant and doesn't
Expand All @@ -288,6 +305,9 @@ def __init__(self, data: AnySelectMenuPayload) -> None:
self.min_values: int = data.get("min_values", 1)
self.max_values: int = data.get("max_values", 1)
self.disabled: bool = data.get("disabled", False)
self.default_values: List[SelectDefaultValue] = [
SelectDefaultValue._from_dict(d) for d in (data.get("default_values") or [])
]

def to_dict(self) -> BaseSelectMenuPayload:
payload: BaseSelectMenuPayload = {
Expand All @@ -301,6 +321,9 @@ def to_dict(self) -> BaseSelectMenuPayload:
if self.placeholder:
payload["placeholder"] = self.placeholder

if self.default_values:
payload["default_values"] = [v.to_dict() for v in self.default_values]

return payload


Expand Down Expand Up @@ -377,6 +400,11 @@ class UserSelectMenu(BaseSelectMenu):
Defaults to 1 and must be between 1 and 25.
disabled: :class:`bool`
Whether the select menu is disabled or not.
default_values: List[:class:`SelectDefaultValue`]
The list of values (users/members) that are selected by default.
If set, the number of items must be within the bounds set by ``min_values`` and ``max_values``.
.. versionadded:: 2.10
"""

__slots__: Tuple[str, ...] = ()
Expand Down Expand Up @@ -412,6 +440,11 @@ class RoleSelectMenu(BaseSelectMenu):
Defaults to 1 and must be between 1 and 25.
disabled: :class:`bool`
Whether the select menu is disabled or not.
default_values: List[:class:`SelectDefaultValue`]
The list of values (roles) that are selected by default.
If set, the number of items must be within the bounds set by ``min_values`` and ``max_values``.
.. versionadded:: 2.10
"""

__slots__: Tuple[str, ...] = ()
Expand Down Expand Up @@ -447,6 +480,11 @@ class MentionableSelectMenu(BaseSelectMenu):
Defaults to 1 and must be between 1 and 25.
disabled: :class:`bool`
Whether the select menu is disabled or not.
default_values: List[:class:`SelectDefaultValue`]
The list of values (users/roles) that are selected by default.
If set, the number of items must be within the bounds set by ``min_values`` and ``max_values``.
.. versionadded:: 2.10
"""

__slots__: Tuple[str, ...] = ()
Expand Down Expand Up @@ -485,6 +523,11 @@ class ChannelSelectMenu(BaseSelectMenu):
channel_types: Optional[List[:class:`ChannelType`]]
A list of channel types that can be selected in this select menu.
If ``None``, channels of all types may be selected.
default_values: List[:class:`SelectDefaultValue`]
The list of values (channels) that are selected by default.
If set, the number of items must be within the bounds set by ``min_values`` and ``max_values``.
.. versionadded:: 2.10
"""

__slots__: Tuple[str, ...] = ("channel_types",)
Expand Down Expand Up @@ -613,6 +656,42 @@ def to_dict(self) -> SelectOptionPayload:
return payload


class SelectDefaultValue:
"""Represents a default value of an auto-populated select menu (currently all
select menu types except :class:`StringSelectMenu`).
Depending on the :attr:`type` attribute, this can represent different types of objects.
.. versionadded:: 2.10
Attributes
----------
id: :class:`int`
The ID of the target object.
type: :class:`SelectDefaultValueType`
The type of the target object.
"""

__slots__: Tuple[str, ...] = ("id", "type")

def __init__(self, id: int, type: SelectDefaultValueType) -> None:
self.id: int = id
self.type: SelectDefaultValueType = type

@classmethod
def _from_dict(cls, data: SelectDefaultValuePayload) -> Self:
return cls(int(data["id"]), try_enum(SelectDefaultValueType, data["type"]))

def to_dict(self) -> SelectDefaultValuePayload:
return {
"id": self.id,
"type": self.type.value,
}

def __repr__(self) -> str:
return f"<SelectDefaultValue id={self.id!r} type={self.type.value!r}>"


class TextInput(Component):
"""Represents a text input from the Discord Bot UI Kit.
Expand Down
Loading

0 comments on commit c7f9738

Please sign in to comment.