Skip to content

Commit

Permalink
Merge branch 'master' of https://github.com/Rapptz/discord.py into v2…
Browse files Browse the repository at this point in the history
…-martine
  • Loading branch information
PredaaA committed Dec 14, 2023
2 parents 16385d0 + 50190e0 commit 67fab42
Show file tree
Hide file tree
Showing 10 changed files with 150 additions and 8 deletions.
28 changes: 27 additions & 1 deletion discord/activity.py
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,10 @@ class Activity(BaseActivity):
The user's current state. For example, "In Game".
details: Optional[:class:`str`]
The detail of the user's current activity.
platform: Optional[:class:`str`]
The user's current platform.
.. versionadded:: 2.4
timestamps: :class:`dict`
A dictionary of timestamps. It contains the following optional keys:
Expand Down Expand Up @@ -197,6 +201,7 @@ class Activity(BaseActivity):
'state',
'details',
'timestamps',
'platform',
'assets',
'party',
'flags',
Expand All @@ -215,6 +220,7 @@ def __init__(self, **kwargs: Any) -> None:
self.state: Optional[str] = kwargs.pop('state', None)
self.details: Optional[str] = kwargs.pop('details', None)
self.timestamps: ActivityTimestamps = kwargs.pop('timestamps', {})
self.platform: Optional[str] = kwargs.pop('platform', None)
self.assets: ActivityAssets = kwargs.pop('assets', {})
self.party: ActivityParty = kwargs.pop('party', {})
self.application_id: Optional[int] = _get_as_snowflake(kwargs, 'application_id')
Expand All @@ -238,6 +244,7 @@ def __repr__(self) -> str:
('type', self.type),
('name', self.name),
('url', self.url),
('platform', self.platform),
('details', self.details),
('application_id', self.application_id),
('session_id', self.session_id),
Expand Down Expand Up @@ -351,13 +358,30 @@ class Game(BaseActivity):
-----------
name: :class:`str`
The game's name.
platform: Optional[:class:`str`]
Where the user is playing from (ie. PS5, Xbox).
.. versionadded:: 2.4
assets: :class:`dict`
A dictionary representing the images and their hover text of a game.
It contains the following optional keys:
- ``large_image``: A string representing the ID for the large image asset.
- ``large_text``: A string representing the text when hovering over the large image asset.
- ``small_image``: A string representing the ID for the small image asset.
- ``small_text``: A string representing the text when hovering over the small image asset.
.. versionadded:: 2.4
"""

__slots__ = ('name', '_end', '_start')
__slots__ = ('name', '_end', '_start', 'platform', 'assets')

def __init__(self, name: str, **extra: Any) -> None:
super().__init__(**extra)
self.name: str = name
self.platform: Optional[str] = extra.get('platform')
self.assets: ActivityAssets = extra.get('assets', {}) or {}

try:
timestamps: ActivityTimestamps = extra['timestamps']
Expand Down Expand Up @@ -408,6 +432,8 @@ def to_dict(self) -> Dict[str, Any]:
'type': ActivityType.playing.value,
'name': str(self.name),
'timestamps': timestamps,
'platform': str(self.platform) if self.platform else None,
'assets': self.assets,
}

def __eq__(self, other: object) -> bool:
Expand Down
2 changes: 1 addition & 1 deletion discord/ext/commands/cooldowns.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,11 @@

from typing import Any, Callable, Deque, Dict, Optional, Union, Generic, TypeVar, TYPE_CHECKING
from discord.enums import Enum
from discord.abc import PrivateChannel
import time
import asyncio
from collections import deque

from ...abc import PrivateChannel
from .errors import MaxConcurrencyReached
from .context import Context
from discord.app_commands import Cooldown as Cooldown
Expand Down
4 changes: 2 additions & 2 deletions discord/ext/tasks/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,12 +111,12 @@ def __init__(self, dt: datetime.datetime, *, loop: asyncio.AbstractEventLoop) ->
self.loop: asyncio.AbstractEventLoop = loop
self.future: asyncio.Future[None] = loop.create_future()
relative_delta = discord.utils.compute_timedelta(dt)
self.handle = loop.call_later(relative_delta, self.future.set_result, True)
self.handle = loop.call_later(relative_delta, self.future.set_result, None)

def recalculate(self, dt: datetime.datetime) -> None:
self.handle.cancel()
relative_delta = discord.utils.compute_timedelta(dt)
self.handle: asyncio.TimerHandle = self.loop.call_later(relative_delta, self.future.set_result, True)
self.handle: asyncio.TimerHandle = self.loop.call_later(relative_delta, self.future.set_result, None)

def wait(self) -> asyncio.Future[Any]:
return self.future
Expand Down
7 changes: 7 additions & 0 deletions discord/http.py
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@ def handle_message_parameters(
mention_author: Optional[bool] = None,
thread_name: str = MISSING,
channel_payload: Dict[str, Any] = MISSING,
applied_tags: Optional[SnowflakeList] = MISSING,
) -> MultipartParameters:
if files is not MISSING and file is not MISSING:
raise TypeError('Cannot mix file and files keyword arguments.')
Expand Down Expand Up @@ -243,6 +244,12 @@ def handle_message_parameters(

payload['attachments'] = attachments_payload

if applied_tags is not MISSING:
if applied_tags is not None:
payload['applied_tags'] = applied_tags
else:
payload['applied_tags'] = []

if channel_payload is not MISSING:
payload = {
'message': payload,
Expand Down
15 changes: 15 additions & 0 deletions discord/interactions.py
Original file line number Diff line number Diff line change
Expand Up @@ -851,6 +851,7 @@ async def edit_message(
view: Optional[View] = MISSING,
allowed_mentions: Optional[AllowedMentions] = MISSING,
delete_after: Optional[float] = None,
suppress_embeds: bool = MISSING,
) -> None:
"""|coro|
Expand Down Expand Up @@ -886,6 +887,13 @@ async def edit_message(
then it is silently ignored.
.. versionadded:: 2.2
suppress_embeds: :class:`bool`
Whether to suppress embeds for the message. This removes
all the embeds if set to ``True``. If set to ``False``
this brings the embeds back if they were suppressed.
Using this parameter requires :attr:`~.Permissions.manage_messages`.
.. versionadded:: 2.4
Raises
-------
Expand Down Expand Up @@ -917,6 +925,12 @@ async def edit_message(
if view is not MISSING and message_id is not None:
state.prevent_view_updates_for(message_id)

if suppress_embeds is not MISSING:
flags = MessageFlags._from_value(0)
flags.suppress_embeds = suppress_embeds
else:
flags = MISSING

adapter = async_context.get()
params = interaction_message_response_params(
type=InteractionResponseType.message_update.value,
Expand All @@ -927,6 +941,7 @@ async def edit_message(
attachments=attachments,
previous_allowed_mentions=parent._state.allowed_mentions,
allowed_mentions=allowed_mentions,
flags=flags,
)

http = parent._state.http
Expand Down
79 changes: 79 additions & 0 deletions discord/message.py
Original file line number Diff line number Diff line change
Expand Up @@ -804,6 +804,20 @@ def jump_url(self) -> str:
guild_id = getattr(self.guild, 'id', '@me')
return f'https://discord.com/channels/{guild_id}/{self.channel.id}/{self.id}'

@property
def thread(self) -> Optional[Thread]:
"""Optional[:class:`Thread`]: The public thread created from this message, if it exists.
.. note::
This does not retrieve archived threads, as they are not retained in the internal
cache. Use :meth:`fetch_thread` instead.
.. versionadded:: 2.4
"""
if self.guild is not None:
return self.guild.get_thread(self.id)

async def fetch(self) -> Message:
"""|coro|
Expand Down Expand Up @@ -1280,6 +1294,40 @@ async def create_thread(
)
return Thread(guild=self.guild, state=self._state, data=data)

async def fetch_thread(self) -> Thread:
"""|coro|
Retrieves the public thread attached to this message.
.. note::
This method is an API call. For general usage, consider :attr:`thread` instead.
.. versionadded:: 2.4
Raises
-------
InvalidData
An unknown channel type was received from Discord
or the guild the thread belongs to is not the same
as the one in this object points to.
HTTPException
Retrieving the thread failed.
NotFound
There is no thread attached to this message.
Forbidden
You do not have permission to fetch this channel.
Returns
--------
:class:`.Thread`
The public thread attached to this message.
"""
if self.guild is None:
raise ValueError('This message does not have guild info attached.')

return await self.guild.fetch_channel(self.id) # type: ignore # Can only be Thread in this case

@overload
async def reply(
self,
Expand Down Expand Up @@ -1572,6 +1620,7 @@ class Message(PartialMessage, Hashable):
'_cs_raw_channel_mentions',
'_cs_raw_role_mentions',
'_cs_system_content',
'_thread',
'tts',
'content',
'webhook_id',
Expand Down Expand Up @@ -1640,6 +1689,21 @@ def __init__(
except AttributeError:
self.guild = state._get_guild(utils._get_as_snowflake(data, 'guild_id'))

self._thread: Optional[Thread] = None

if self.guild is not None:
try:
thread = data['thread']
except KeyError:
pass
else:
self._thread = self.guild.get_thread(int(thread['id']))

if self._thread is not None:
self._thread._update(thread)
else:
self._thread = Thread(guild=self.guild, state=state, data=thread)

self.interaction: Optional[MessageInteraction] = None

try:
Expand Down Expand Up @@ -1982,6 +2046,21 @@ def edited_at(self) -> Optional[datetime.datetime]:
"""Optional[:class:`datetime.datetime`]: An aware UTC datetime object containing the edited time of the message."""
return self._edited_timestamp

@property
def thread(self) -> Optional[Thread]:
"""Optional[:class:`Thread`]: The public thread created from this message, if it exists.
.. note::
For messages received via the gateway this does not retrieve archived threads, as they
are not retained in the internal cache. Use :meth:`fetch_thread` instead.
.. versionadded:: 2.4
"""
if self.guild is not None:
# Fall back to guild threads in case one was created after the message
return self._thread or self.guild.get_thread(self.id)

def is_system(self) -> bool:
""":class:`bool`: Whether the message is a system message.
Expand Down
1 change: 1 addition & 0 deletions discord/types/activity.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ class Activity(_BaseActivity, total=False):
state: Optional[str]
details: Optional[str]
timestamps: ActivityTimestamps
platform: Optional[str]
assets: ActivityAssets
party: ActivityParty
application_id: Snowflake
Expand Down
2 changes: 2 additions & 0 deletions discord/types/message.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
from .components import Component
from .interactions import MessageInteraction
from .sticker import StickerItem
from .threads import Thread


class PartialMessage(TypedDict):
Expand Down Expand Up @@ -146,6 +147,7 @@ class Message(PartialMessage):
components: NotRequired[List[Component]]
position: NotRequired[int]
role_subscription_data: NotRequired[RoleSubscriptionData]
thread: NotRequired[Thread]


AllowedMentionType = Literal['roles', 'users', 'everyone']
Expand Down
14 changes: 13 additions & 1 deletion discord/webhook/async_.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
from ..partial_emoji import PartialEmoji
from ..http import Route, handle_message_parameters, MultipartParameters, HTTPClient, json_or_text
from ..mixins import Hashable
from ..channel import TextChannel, ForumChannel, PartialMessageable
from ..channel import TextChannel, ForumChannel, PartialMessageable, ForumTag
from ..file import File

__all__ = (
Expand Down Expand Up @@ -88,6 +88,7 @@
PartialChannel as PartialChannelPayload,
)
from ..types.emoji import PartialEmoji as PartialEmojiPayload
from ..types.snowflake import SnowflakeList

BE = TypeVar('BE', bound=BaseException)
_State = Union[ConnectionState, '_WebhookState']
Expand Down Expand Up @@ -1639,6 +1640,7 @@ async def send(
wait: bool = False,
suppress_embeds: bool = False,
silent: bool = False,
applied_tags: List[ForumTag] = MISSING,
) -> Optional[WebhookMessage]:
"""|coro|
Expand Down Expand Up @@ -1724,6 +1726,10 @@ async def send(
in the UI, but will not actually send a notification.
.. versionadded:: 2.2
applied_tags: List[:class:`ForumTag`]
Tags to apply to the thread if the webhook belongs to a :class:`~discord.ForumChannel`.
.. versionadded:: 2.4
Raises
--------
Expand Down Expand Up @@ -1782,6 +1788,11 @@ async def send(
if thread_name is not MISSING and thread is not MISSING:
raise TypeError('Cannot mix thread_name and thread keyword arguments.')

if applied_tags is MISSING:
applied_tag_ids = MISSING
else:
applied_tag_ids: SnowflakeList = [tag.id for tag in applied_tags]

with handle_message_parameters(
content=content,
username=username,
Expand All @@ -1796,6 +1807,7 @@ async def send(
thread_name=thread_name,
allowed_mentions=allowed_mentions,
previous_allowed_mentions=previous_mentions,
applied_tags=applied_tag_ids,
) as params:
adapter = async_context.get()
thread_id: Optional[int] = None
Expand Down
6 changes: 3 additions & 3 deletions docs/api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2825,7 +2825,7 @@ of :class:`enum.Enum`.
set to an unspecified proxy object with 3 attributes:

- ``automod_rule_name``: The name of the automod rule that was triggered.
- ``automod_rule_trigger``: A :class:`AutoModRuleTriggerType` representation of the rule type that was triggered.
- ``automod_rule_trigger_type``: A :class:`AutoModRuleTriggerType` representation of the rule type that was triggered.
- ``channel``: The channel in which the automod rule was triggered.

When this is the action, :attr:`AuditLogEntry.changes` is empty.
Expand All @@ -2843,7 +2843,7 @@ of :class:`enum.Enum`.
set to an unspecified proxy object with 3 attributes:

- ``automod_rule_name``: The name of the automod rule that was triggered.
- ``automod_rule_trigger``: A :class:`AutoModRuleTriggerType` representation of the rule type that was triggered.
- ``automod_rule_trigger_type``: A :class:`AutoModRuleTriggerType` representation of the rule type that was triggered.
- ``channel``: The channel in which the automod rule was triggered.

When this is the action, :attr:`AuditLogEntry.changes` is empty.
Expand All @@ -2861,7 +2861,7 @@ of :class:`enum.Enum`.
set to an unspecified proxy object with 3 attributes:

- ``automod_rule_name``: The name of the automod rule that was triggered.
- ``automod_rule_trigger``: A :class:`AutoModRuleTriggerType` representation of the rule type that was triggered.
- ``automod_rule_trigger_type``: A :class:`AutoModRuleTriggerType` representation of the rule type that was triggered.
- ``channel``: The channel in which the automod rule was triggered.

When this is the action, :attr:`AuditLogEntry.changes` is empty.
Expand Down

0 comments on commit 67fab42

Please sign in to comment.