Skip to content

Commit

Permalink
Merge branch 'master' into feat/forward
Browse files Browse the repository at this point in the history
Signed-off-by: Snipy7374 <[email protected]>
  • Loading branch information
Snipy7374 authored Nov 14, 2024
2 parents c572922 + fbfc814 commit 0d32187
Show file tree
Hide file tree
Showing 98 changed files with 2,806 additions and 361 deletions.
2 changes: 2 additions & 0 deletions .github/actions/setup-env/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ runs:
cache: false
cache-dependency-path: ${{ inputs.cache-dependency-path }}
enable-pep582: false # Disable PEP 582 package loading globally
env:
PDM_DEPS: 'importlib-metadata<8; python_version < "3.10"'

- name: Disable PDM version check
shell: bash
Expand Down
1 change: 1 addition & 0 deletions changelog/1012.feature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
:class:`Interaction`\s now always have a proper :attr:`~Interaction.channel` attribute, even when the bot is not part of the guild or cannot access the channel due to other reasons.
2 changes: 1 addition & 1 deletion changelog/1113.feature.rst
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
Support application subscriptions (see the :ddocs:`official docs <monetization/overview>` for more info).
Support application subscriptions and one-time purchases (see the :ddocs:`official docs <monetization/overview>` for more info).
- New types: :class:`SKU`, :class:`Entitlement`.
- New :attr:`Interaction.entitlements` attribute, and :meth:`InteractionResponse.require_premium` response type.
- New events: :func:`on_entitlement_create`, :func:`on_entitlement_update`, :func:`on_entitlement_delete`.
Expand Down
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: 1 addition & 0 deletions changelog/1142.bugfix.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Support fetching invites with ``null`` channel (e.g. friend invites).
1 change: 1 addition & 0 deletions changelog/1142.feature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add :attr:`Invite.type`.
1 change: 1 addition & 0 deletions changelog/1160.feature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
:attr:`InteractionReference.user` can now be a :class:`Member` in guild contexts.
1 change: 1 addition & 0 deletions changelog/1174.feature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Support banning multiple users at once using :meth:`Guild.bulk_ban`.
6 changes: 6 additions & 0 deletions changelog/1175.feature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
Add the new poll discord API feature. This includes the following new classes and events:

- New types: :class:`Poll`, :class:`PollAnswer`, :class:`PollMedia`, :class:`RawPollVoteActionEvent` and :class:`PollLayoutType`.
- Edited :meth:`abc.Messageable.send`, :meth:`Webhook.send`, :meth:`ext.commands.Context.send` and :meth:`disnake.InteractionResponse.send_message` to be able to send polls.
- Edited :class:`Message` to store a new :attr:`Message.poll` attribute for polls.
- Edited :class:`Event` to contain the new :func:`on_poll_vote_add`, :func:`on_poll_vote_remove`, :func:`on_raw_poll_vote_add` and :func:`on_raw_poll_vote_remove`.
5 changes: 5 additions & 0 deletions changelog/1186.feature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Support application subscriptions and one-time purchases (see the :ddocs:`official docs <monetization/overview>` for more info).
- New types: :class:`SKU`, :class:`Entitlement`.
- New :attr:`Interaction.entitlements` attribute, and :meth:`InteractionResponse.require_premium` response type.
- New events: :func:`on_entitlement_create`, :func:`on_entitlement_update`, :func:`on_entitlement_delete`.
- New :class:`Client` methods: :meth:`~Client.skus`, :meth:`~Client.entitlements`, :meth:`~Client.create_entitlement`.
1 change: 1 addition & 0 deletions changelog/1189.bugfix.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fix base URL for stickers with :attr:`StickerFormatType.gif`.
1 change: 1 addition & 0 deletions changelog/1196.misc.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Remove ``disnake[discord]`` extra; the shim is deprecated, and has not been updated for several versions.
5 changes: 5 additions & 0 deletions changelog/1197.feature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Implement new :attr:`Message.type`\s:
- :attr:`MessageType.guild_incident_alert_mode_enabled`
- :attr:`MessageType.guild_incident_alert_mode_disabled`
- :attr:`MessageType.guild_incident_report_raid`
- :attr:`MessageType.guild_incident_report_false_alarm`
1 change: 1 addition & 0 deletions changelog/1211.feature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add :attr:`Permissions.use_external_apps`, and a new :attr:`Permissions.apps` category to match the Discord client UI.
1 change: 1 addition & 0 deletions changelog/1218.feature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add new :attr:`Attachment.title` attribute.
1 change: 1 addition & 0 deletions changelog/1220.feature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add :attr:`AppInfo.approximate_guild_count` and :attr:`AppInfo.approximate_user_install_count`.
1 change: 1 addition & 0 deletions changelog/1221.feature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add new :meth:`.Client.fetch_sticker_pack` method.
2 changes: 2 additions & 0 deletions changelog/1233.feature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
For interactions in private channels, :attr:`Interaction.channel` is now always a proper :class:`DMChannel` or :class:`GroupChannel` object, instead of :class:`PartialMessageable`.
- This also applies to other channel objects in interactions, e.g. channel parameters in slash commands, or :attr:`ui.ChannelSelect.values`.
4 changes: 4 additions & 0 deletions changelog/889.feature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Add support for avatar decorations using:
- :attr:`User.avatar_decoration`
- :attr:`Member.display_avatar_decoration`
- :attr:`Member.guild_avatar_decoration`
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`.
1 change: 1 addition & 0 deletions disnake/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
from .partial_emoji import *
from .permissions import *
from .player import *
from .poll import *
from .raw_models import *
from .reaction import *
from .role import *
Expand Down
39 changes: 30 additions & 9 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 All @@ -64,16 +63,17 @@
from typing_extensions import Self

from .asset import Asset
from .channel import CategoryChannel, DMChannel, PartialMessageable
from .channel import CategoryChannel, DMChannel, GroupChannel, PartialMessageable
from .client import Client
from .embeds import Embed
from .emoji import Emoji
from .enums import InviteTarget
from .guild import Guild, GuildMessageable
from .guild import Guild, GuildChannel as AnyGuildChannel, GuildMessageable
from .guild_scheduled_event import GuildScheduledEvent
from .iterators import HistoryIterator
from .member import Member
from .message import Message, MessageReference, PartialMessage
from .poll import Poll
from .state import ConnectionState
from .threads import AnyThreadArchiveDuration, ForumTag
from .types.channel import (
Expand All @@ -89,7 +89,10 @@
from .user import ClientUser
from .voice_region import VoiceRegion

MessageableChannel = Union[GuildMessageable, DMChannel, PartialMessageable]
MessageableChannel = Union[GuildMessageable, DMChannel, GroupChannel, PartialMessageable]
# include non-messageable channels, e.g. category/forum
AnyChannel = Union[MessageableChannel, AnyGuildChannel]

SnowflakeTime = Union["Snowflake", datetime]

MISSING = utils.MISSING
Expand Down Expand Up @@ -175,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 @@ -640,6 +644,7 @@ def _apply_implict_permissions(self, base: Permissions) -> None:
if not base.send_messages:
base.send_tts_messages = False
base.send_voice_messages = False
base.send_polls = False
base.mention_everyone = False
base.embed_links = False
base.attach_files = False
Expand Down Expand Up @@ -887,13 +892,15 @@ async def set_permissions(
request_to_speak: Optional[bool] = ...,
send_messages: Optional[bool] = ...,
send_messages_in_threads: Optional[bool] = ...,
send_polls: Optional[bool] = ...,
send_tts_messages: Optional[bool] = ...,
send_voice_messages: Optional[bool] = ...,
speak: Optional[bool] = ...,
start_embedded_activities: Optional[bool] = ...,
stream: Optional[bool] = ...,
use_application_commands: Optional[bool] = ...,
use_embedded_activities: Optional[bool] = ...,
use_external_apps: Optional[bool] = ...,
use_external_emojis: Optional[bool] = ...,
use_external_sounds: Optional[bool] = ...,
use_external_stickers: Optional[bool] = ...,
Expand Down Expand Up @@ -1434,6 +1441,7 @@ async def send(
mention_author: bool = ...,
view: View = ...,
components: Components[MessageUIComponent] = ...,
poll: Poll = ...,
) -> Message:
...

Expand All @@ -1455,6 +1463,7 @@ async def send(
mention_author: bool = ...,
view: View = ...,
components: Components[MessageUIComponent] = ...,
poll: Poll = ...,
) -> Message:
...

Expand All @@ -1476,6 +1485,7 @@ async def send(
mention_author: bool = ...,
view: View = ...,
components: Components[MessageUIComponent] = ...,
poll: Poll = ...,
) -> Message:
...

Expand All @@ -1497,6 +1507,7 @@ async def send(
mention_author: bool = ...,
view: View = ...,
components: Components[MessageUIComponent] = ...,
poll: Poll = ...,
) -> Message:
...

Expand All @@ -1519,6 +1530,7 @@ async def send(
mention_author: Optional[bool] = None,
view: Optional[View] = None,
components: Optional[Components[MessageUIComponent]] = None,
poll: Optional[Poll] = None,
):
"""|coro|
Expand All @@ -1527,7 +1539,7 @@ async def send(
The content must be a type that can convert to a string through ``str(content)``.
At least one of ``content``, ``embed``/``embeds``, ``file``/``files``,
``stickers``, ``components``, or ``view`` must be provided.
``stickers``, ``components``, ``poll`` or ``view`` must be provided.
To upload a single file, the ``file`` parameter should be used with a
single :class:`.File` object. To upload multiple files, the ``files``
Expand Down Expand Up @@ -1628,6 +1640,11 @@ async def send(
.. versionadded:: 2.9
poll: :class:`.Poll`
The poll to send with the message.
.. versionadded:: 2.10
Raises
------
HTTPException
Expand Down Expand Up @@ -1680,6 +1697,10 @@ async def send(
if stickers is not None:
stickers_payload = [sticker.id for sticker in stickers]

poll_payload = None
if poll:
poll_payload = poll._to_dict()

allowed_mentions_payload = None
if allowed_mentions is None:
allowed_mentions_payload = state.allowed_mentions and state.allowed_mentions.to_dict()
Expand All @@ -1703,16 +1724,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 Expand Up @@ -1741,6 +1760,7 @@ async def send(
message_reference=reference_payload,
stickers=stickers_payload,
components=components_payload,
poll=poll_payload,
flags=flags_payload,
)
finally:
Expand All @@ -1757,6 +1777,7 @@ async def send(
message_reference=reference_payload,
stickers=stickers_payload,
components=components_payload,
poll=poll_payload,
flags=flags_payload,
)

Expand Down
19 changes: 15 additions & 4 deletions disnake/appinfo.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,8 +98,7 @@ class AppInfo:
.. versionadded:: 1.3
guild_id: Optional[:class:`int`]
If this application is a game sold on Discord,
this field will be the guild to which it has been linked to.
The ID of the guild associated with the application, if any.
.. versionadded:: 1.3
Expand Down Expand Up @@ -151,6 +150,15 @@ class AppInfo:
in the guild role verification configuration.
.. versionadded:: 2.8
approximate_guild_count: :class:`int`
The approximate number of guilds the application is installed to.
.. versionadded:: 2.10
approximate_user_install_count: :class:`int`
The approximate number of users that have installed the application
(for user-installable apps).
.. versionadded:: 2.10
"""

__slots__ = (
Expand All @@ -177,6 +185,8 @@ class AppInfo:
"install_params",
"custom_install_url",
"role_connections_verification_url",
"approximate_guild_count",
"approximate_user_install_count",
)

def __init__(self, state: ConnectionState, data: AppInfoPayload) -> None:
Expand Down Expand Up @@ -218,6 +228,8 @@ def __init__(self, state: ConnectionState, data: AppInfoPayload) -> None:
self.role_connections_verification_url: Optional[str] = data.get(
"role_connections_verification_url"
)
self.approximate_guild_count: int = data.get("approximate_guild_count", 0)
self.approximate_user_install_count: int = data.get("approximate_user_install_count", 0)

def __repr__(self) -> str:
return (
Expand Down Expand Up @@ -245,8 +257,7 @@ def cover_image(self) -> Optional[Asset]:

@property
def guild(self) -> Optional[Guild]:
"""Optional[:class:`Guild`]: If this application is a game sold on Discord,
this field will be the guild to which it has been linked
"""Optional[:class:`Guild`]: The guild associated with the application, if any.
.. versionadded:: 1.3
"""
Expand Down
13 changes: 13 additions & 0 deletions disnake/asset.py
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,9 @@ class Asset(AssetMixin):

BASE = "https://cdn.discordapp.com"

# only used in special cases where Discord doesn't provide an asset on the CDN url
BASE_MEDIA = "https://media.discordapp.net"

def __init__(self, state: AnyState, *, url: str, key: str, animated: bool = False) -> None:
self._state: AnyState = state
self._url: str = url
Expand Down Expand Up @@ -314,6 +317,16 @@ def _from_guild_scheduled_event_image(
animated=False,
)

@classmethod
def _from_avatar_decoration(cls, state: AnyState, avatar_decoration_asset: str) -> Self:
animated = avatar_decoration_asset.startswith("a_")
return cls(
state,
url=f"{cls.BASE}/avatar-decoration-presets/{avatar_decoration_asset}.png?size=1024",
key=avatar_decoration_asset,
animated=animated,
)

def __str__(self) -> str:
return self._url

Expand Down
9 changes: 7 additions & 2 deletions disnake/audit_logs.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@
DefaultReaction as DefaultReactionPayload,
PermissionOverwrite as PermissionOverwritePayload,
)
from .types.invite import Invite as InvitePayload
from .types.role import Role as RolePayload
from .types.snowflake import Snowflake
from .types.threads import ForumTag as ForumTagPayload
Expand Down Expand Up @@ -799,15 +800,19 @@ def _convert_target_invite(self, target_id: int) -> Invite:
# so figure out which change has the full invite data
changeset = self.before if self.action is enums.AuditLogAction.invite_delete else self.after

fake_payload = {
fake_payload: InvitePayload = {
"max_age": changeset.max_age,
"max_uses": changeset.max_uses,
"code": changeset.code,
"temporary": changeset.temporary,
"uses": changeset.uses,
"type": 0,
"channel": None,
}

obj = Invite(state=self._state, data=fake_payload, guild=self.guild, channel=changeset.channel) # type: ignore
obj = Invite(
state=self._state, data=fake_payload, guild=self.guild, channel=changeset.channel
)
try:
obj.inviter = changeset.inviter
except AttributeError:
Expand Down
8 changes: 7 additions & 1 deletion disnake/bans.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,20 @@

from __future__ import annotations

from typing import TYPE_CHECKING, NamedTuple, Optional
from typing import TYPE_CHECKING, NamedTuple, Optional, Sequence

__all__ = ("BanEntry",)

if TYPE_CHECKING:
from .abc import Snowflake
from .user import User


class BanEntry(NamedTuple):
reason: Optional[str]
user: "User"


class BulkBanResult(NamedTuple):
banned: Sequence[Snowflake]
failed: Sequence[Snowflake]
Loading

0 comments on commit 0d32187

Please sign in to comment.