diff --git a/discord/abc.py b/discord/abc.py
index fd2dc4bb9..3b7027394 100644
--- a/discord/abc.py
+++ b/discord/abc.py
@@ -51,6 +51,7 @@ from .permissions import PermissionOverwrite, Permissions
from .role import Role
from .invite import Invite
from .file import File
+from .http import handle_message_parameters
from .voice_client import VoiceClient, VoiceProtocol
from .sticker import GuildSticker, StickerItem
from . import utils
@@ -1330,107 +1331,40 @@ class Messageable:
channel = await self._get_channel()
state = self._state
content = str(content) if content is not None else None
-
- if embed is not None and embeds is not None:
- raise InvalidArgument('cannot pass both embed and embeds parameter to send()')
-
- if embed is not None:
- embed = embed.to_dict()
-
- elif embeds is not None:
- if len(embeds) > 10:
- raise InvalidArgument('embeds parameter must be a list of up to 10 elements')
- embeds = [embed.to_dict() for embed in embeds]
+ previous_allowed_mention = state.allowed_mentions
if stickers is not None:
stickers = [sticker.id for sticker in stickers]
-
- if allowed_mentions is not None:
- if state.allowed_mentions is not None:
- allowed_mentions = state.allowed_mentions.merge(allowed_mentions).to_dict()
- else:
- allowed_mentions = allowed_mentions.to_dict()
else:
- allowed_mentions = state.allowed_mentions and state.allowed_mentions.to_dict()
-
- if mention_author is not None:
- allowed_mentions = allowed_mentions or AllowedMentions().to_dict()
- allowed_mentions['replied_user'] = bool(mention_author)
+ stickers = MISSING
if reference is not None:
try:
reference = reference.to_message_reference_dict()
except AttributeError:
raise InvalidArgument('reference parameter must be Message, MessageReference, or PartialMessage') from None
-
- if view:
- if not hasattr(view, '__discord_ui_view__'):
- raise InvalidArgument(f'view parameter must be View not {view.__class__!r}')
-
- components = view.to_components()
else:
- components = None
+ reference = MISSING
- if file is not None and files is not None:
- raise InvalidArgument('cannot pass both file and files parameter to send()')
+ if view and not hasattr(view, '__discord_ui_view__'):
+ raise InvalidArgument(f'view parameter must be View not {view.__class__!r}')
- if file is not None:
- if not isinstance(file, File):
- raise InvalidArgument('file parameter must be File')
-
- try:
- data = await state.http.send_files(
- channel.id,
- files=[file],
- allowed_mentions=allowed_mentions,
- content=content,
- tts=tts,
- embed=embed,
- embeds=embeds,
- nonce=nonce,
- message_reference=reference,
- stickers=stickers,
- components=components,
- )
- finally:
- file.close()
-
- elif files is not None:
- if len(files) > 10:
- raise InvalidArgument('files parameter must be a list of up to 10 elements')
- elif not all(isinstance(file, File) for file in files):
- raise InvalidArgument('files parameter must be a list of File')
-
- try:
- data = await state.http.send_files(
- channel.id,
- files=files,
- content=content,
- tts=tts,
- embed=embed,
- embeds=embeds,
- nonce=nonce,
- allowed_mentions=allowed_mentions,
- message_reference=reference,
- stickers=stickers,
- components=components,
- )
- finally:
- for f in files:
- f.close()
- else:
- data = await state.http.send_message(
- channel.id,
- content,
- tts=tts,
- embed=embed,
- embeds=embeds,
- nonce=nonce,
- allowed_mentions=allowed_mentions,
- message_reference=reference,
- stickers=stickers,
- components=components,
- )
+ with handle_message_parameters(
+ content=content,
+ tts=tts,
+ file=file if file is not None else MISSING,
+ files=files if files is not None else MISSING,
+ embed=embed if embed is not None else MISSING,
+ embeds=embeds if embeds is not None else MISSING,
+ nonce=nonce,
+ allowed_mentions=allowed_mentions,
+ message_reference=reference,
+ previous_allowed_mentions=previous_allowed_mention,
+ mention_author=mention_author,
+ stickers=stickers,
+ view=view,
+ ) as params:
+ data = await state.http.send_message(channel.id, params=params)
ret = state.create_message(channel=channel, data=data)
if view:
diff --git a/discord/http.py b/discord/http.py
index 04c90c89f..f38ca593a 100644
--- a/discord/http.py
+++ b/discord/http.py
@@ -35,14 +35,15 @@ from typing import (
Iterable,
List,
Literal,
+ NamedTuple,
Optional,
+ overload,
Sequence,
- TYPE_CHECKING,
Tuple,
+ TYPE_CHECKING,
Type,
TypeVar,
Union,
- overload,
)
from urllib.parse import quote as _uriquote
import weakref
@@ -58,6 +59,11 @@ _log = logging.getLogger(__name__)
if TYPE_CHECKING:
from .file import File
+ from .ui.view import View
+ from .embeds import Embed
+ from .mentions import AllowedMentions
+ from .message import Attachment
+ from .flags import MessageFlags
from .enums import (
AuditLogAction,
InteractionResponseType,
@@ -110,6 +116,149 @@ async def json_or_text(response: aiohttp.ClientResponse) -> Union[Dict[str, Any]
return text
+class MultipartParameters(NamedTuple):
+ payload: Optional[Dict[str, Any]]
+ multipart: Optional[List[Dict[str, Any]]]
+ files: Optional[List[File]]
+
+ def __enter__(self):
+ return self
+
+ def __exit__(
+ self,
+ exc_type: Optional[Type[BE]],
+ exc: Optional[BE],
+ traceback: Optional[TracebackType],
+ ) -> None:
+ if self.files:
+ for file in self.files:
+ file.close()
+
+
+def handle_message_parameters(
+ content: Optional[str] = MISSING,
+ *,
+ username: str = MISSING,
+ avatar_url: Any = MISSING,
+ tts: bool = False,
+ nonce: Optional[Union[int, str]] = None,
+ flags: MessageFlags = MISSING,
+ file: File = MISSING,
+ files: List[File] = MISSING,
+ embed: Optional[Embed] = MISSING,
+ embeds: List[Embed] = MISSING,
+ attachments: List[Attachment] = MISSING,
+ view: Optional[View] = MISSING,
+ allowed_mentions: Optional[AllowedMentions] = MISSING,
+ message_reference: Optional[message.MessageReference] = MISSING,
+ stickers: Optional[SnowflakeList] = MISSING,
+ previous_allowed_mentions: Optional[AllowedMentions] = None,
+ mention_author: Optional[bool] = None,
+) -> MultipartParameters:
+ if files is not MISSING and file is not MISSING:
+ raise TypeError('Cannot mix file and files keyword arguments.')
+ if embeds is not MISSING and embed is not MISSING:
+ raise TypeError('Cannot mix embed and embeds keyword arguments.')
+
+ payload = {}
+ if embeds is not MISSING:
+ if len(embeds) > 10:
+ raise InvalidArgument('embeds has a maximum of 10 elements.')
+ payload['embeds'] = [e.to_dict() for e in embeds]
+
+ if embed is not MISSING:
+ if embed is None:
+ payload['embeds'] = []
+ else:
+ payload['embeds'] = [embed.to_dict()]
+
+ if content is not MISSING:
+ if content is not None:
+ payload['content'] = str(content)
+ else:
+ payload['content'] = None
+
+ if view is not MISSING:
+ if view is not None:
+ payload['components'] = view.to_components()
+ else:
+ payload['components'] = []
+
+ if nonce is not MISSING:
+ payload['nonce'] = str(nonce)
+
+ if message_reference is not MISSING:
+ payload['message_reference'] = message_reference
+
+ if attachments is not MISSING:
+ # Note: This will be overwritten if file or files is provided
+ # However, right now this is only passed via Message.edit not Messageable.send
+ payload['attachments'] = [a.to_dict() for a in attachments]
+
+ if stickers is not MISSING:
+ if stickers is not None:
+ payload['sticker_ids'] = stickers
+ else:
+ payload['sticker_ids'] = []
+
+ payload['tts'] = tts
+ if avatar_url:
+ payload['avatar_url'] = str(avatar_url)
+ if username:
+ payload['username'] = username
+
+ if flags is not MISSING:
+ payload['flags'] = flags.value
+
+ if allowed_mentions:
+ if previous_allowed_mentions is not None:
+ payload['allowed_mentions'] = previous_allowed_mentions.merge(allowed_mentions).to_dict()
+ else:
+ payload['allowed_mentions'] = allowed_mentions.to_dict()
+ elif previous_allowed_mentions is not None:
+ payload['allowed_mentions'] = previous_allowed_mentions.to_dict()
+
+ if mention_author is not None:
+ try:
+ payload['allowed_mentions']['replied_user'] = mention_author
+ except KeyError:
+ pass
+
+ multipart = []
+ if file is not MISSING:
+ files = [file]
+
+ if files:
+ for index, file in enumerate(files):
+ attachments_payload = []
+ for index, file in enumerate(files):
+ attachment = {
+ 'id': index,
+ 'filename': file.filename,
+ }
+
+ if file.description is not None:
+ attachment['description'] = file.description
+
+ attachments_payload.append(attachment)
+
+ payload['attachments'] = attachments_payload
+
+ multipart.append({'name': 'payload_json', 'value': utils._to_json(payload)})
+ payload = None
+ for index, file in enumerate(files):
+ multipart.append(
+ {
+ 'name': f'files[{index}]',
+ 'value': file.fp,
+ 'filename': file.filename,
+ 'content_type': 'application/octet-stream',
+ }
+ )
+
+ return MultipartParameters(payload=payload, multipart=multipart, files=files)
+
+
class Route:
BASE: ClassVar[str] = 'https://discord.com/api/v8'
@@ -268,7 +417,7 @@ class HTTPClient:
if form:
# with quote_fields=True '[' and ']' in file field names are escaped, which discord does not support
- form_data = aiohttp.FormData(quote_fields=False)
+ form_data = aiohttp.FormData(quote_fields=False)
for params in form:
form_data.add_field(**params)
kwargs['data'] = form_data
@@ -417,144 +566,18 @@ class HTTPClient:
def send_message(
self,
channel_id: Snowflake,
- content: Optional[str],
*,
- tts: bool = False,
- embed: Optional[embed.Embed] = None,
- embeds: Optional[List[embed.Embed]] = None,
- nonce: Optional[str] = None,
- allowed_mentions: Optional[message.AllowedMentions] = None,
- message_reference: Optional[message.MessageReference] = None,
- stickers: Optional[List[sticker.StickerItem]] = None,
- components: Optional[List[components.Component]] = None,
+ params: MultipartParameters,
) -> Response[message.Message]:
r = Route('POST', '/channels/{channel_id}/messages', channel_id=channel_id)
- payload = {}
-
- if content:
- payload['content'] = content
-
- if tts:
- payload['tts'] = True
-
- if embed:
- payload['embeds'] = [embed]
-
- if embeds:
- payload['embeds'] = embeds
-
- if nonce:
- payload['nonce'] = nonce
-
- if allowed_mentions:
- payload['allowed_mentions'] = allowed_mentions
-
- if message_reference:
- payload['message_reference'] = message_reference
-
- if components:
- payload['components'] = components
-
- if stickers:
- payload['sticker_ids'] = stickers
-
- return self.request(r, json=payload)
+ if params.files:
+ return self.request(r, files=params.files, form=params.multipart)
+ else:
+ return self.request(r, json=params.payload)
def send_typing(self, channel_id: Snowflake) -> Response[None]:
return self.request(Route('POST', '/channels/{channel_id}/typing', channel_id=channel_id))
- def send_multipart_helper(
- self,
- route: Route,
- *,
- files: Sequence[File],
- content: Optional[str] = None,
- tts: bool = False,
- embed: Optional[embed.Embed] = None,
- embeds: Optional[Iterable[Optional[embed.Embed]]] = None,
- nonce: Optional[str] = None,
- allowed_mentions: Optional[message.AllowedMentions] = None,
- message_reference: Optional[message.MessageReference] = None,
- stickers: Optional[List[sticker.StickerItem]] = None,
- components: Optional[List[components.Component]] = None,
- ) -> Response[message.Message]:
- form = []
-
- payload: Dict[str, Any] = {'tts': tts}
- if content:
- payload['content'] = content
- if embed:
- payload['embeds'] = [embed]
- if embeds:
- payload['embeds'] = embeds
- if nonce:
- payload['nonce'] = nonce
- if allowed_mentions:
- payload['allowed_mentions'] = allowed_mentions
- if message_reference:
- payload['message_reference'] = message_reference
- if components:
- payload['components'] = components
- if stickers:
- payload['sticker_ids'] = stickers
- if files:
- attachments = []
- for index, file in enumerate(files):
- attachment = {
- "id": index,
- "filename": file.filename,
- }
-
- if file.description is not None:
- attachment["description"] = file.description
-
- attachments.append(attachment)
-
- payload['attachments'] = attachments
-
- form.append({'name': 'payload_json', 'value': utils._to_json(payload)})
- for index, file in enumerate(files):
- form.append(
- {
- 'name': f'files[{index}]',
- 'value': file.fp,
- 'filename': file.filename,
- 'content_type': 'image/png',
- }
- )
-
- return self.request(route, form=form, files=files)
-
- def send_files(
- self,
- channel_id: Snowflake,
- *,
- files: Sequence[File],
- content: Optional[str] = None,
- tts: bool = False,
- embed: Optional[embed.Embed] = None,
- embeds: Optional[List[embed.Embed]] = None,
- nonce: Optional[str] = None,
- allowed_mentions: Optional[message.AllowedMentions] = None,
- message_reference: Optional[message.MessageReference] = None,
- stickers: Optional[List[sticker.StickerItem]] = None,
- components: Optional[List[components.Component]] = None,
- ) -> Response[message.Message]:
- r = Route('POST', '/channels/{channel_id}/messages', channel_id=channel_id)
- return self.send_multipart_helper(
- r,
- files=files,
- content=content,
- tts=tts,
- embed=embed,
- embeds=embeds,
- nonce=nonce,
- allowed_mentions=allowed_mentions,
- message_reference=message_reference,
- stickers=stickers,
- components=components,
- )
-
def delete_message(
self, channel_id: Snowflake, message_id: Snowflake, *, reason: Optional[str] = None
) -> Response[None]:
@@ -571,9 +594,9 @@ class HTTPClient:
return self.request(r, json=payload, reason=reason)
- def edit_message(self, channel_id: Snowflake, message_id: Snowflake, **fields: Any) -> Response[message.Message]:
+ def edit_message(self, channel_id: Snowflake, message_id: Snowflake, *, params: MultipartParameters) -> Response[message.Message]:
r = Route('PATCH', '/channels/{channel_id}/messages/{message_id}', channel_id=channel_id, message_id=message_id)
- return self.request(r, json=fields)
+ return self.request(r, json=params.payload)
def add_reaction(self, channel_id: Snowflake, message_id: Snowflake, emoji: str) -> Response[None]:
r = Route(
@@ -1241,7 +1264,11 @@ class HTTPClient:
)
def modify_guild_sticker(
- self, guild_id: Snowflake, sticker_id: Snowflake, payload: sticker.EditGuildSticker, reason: Optional[str],
+ self,
+ guild_id: Snowflake,
+ sticker_id: Snowflake,
+ payload: sticker.EditGuildSticker,
+ reason: Optional[str],
) -> Response[sticker.GuildSticker]:
return self.request(
Route('PATCH', '/guilds/{guild_id}/stickers/{sticker_id}', guild_id=guild_id, sticker_id=sticker_id),
@@ -1706,9 +1733,7 @@ class HTTPClient:
def get_global_commands(self, application_id: Snowflake) -> Response[List[command.ApplicationCommand]]:
return self.request(Route('GET', '/applications/{application_id}/commands', application_id=application_id))
- def get_global_command(
- self, application_id: Snowflake, command_id: Snowflake
- ) -> Response[command.ApplicationCommand]:
+ def get_global_command(self, application_id: Snowflake, command_id: Snowflake) -> Response[command.ApplicationCommand]:
r = Route(
'GET',
'/applications/{application_id}/commands/{command_id}',
@@ -1750,9 +1775,7 @@ class HTTPClient:
)
return self.request(r)
- def bulk_upsert_global_commands(
- self, application_id: Snowflake, payload
- ) -> Response[List[command.ApplicationCommand]]:
+ def bulk_upsert_global_commands(self, application_id: Snowflake, payload) -> Response[List[command.ApplicationCommand]]:
r = Route('PUT', '/applications/{application_id}/commands', application_id=application_id)
return self.request(r, json=payload)
@@ -1849,160 +1872,6 @@ class HTTPClient:
)
return self.request(r, json=payload)
- # Interaction responses
-
- def _edit_webhook_helper(
- self,
- route: Route,
- file: Optional[File] = None,
- content: Optional[str] = None,
- embeds: Optional[List[embed.Embed]] = None,
- allowed_mentions: Optional[message.AllowedMentions] = None,
- ):
-
- payload: Dict[str, Any] = {}
- if content:
- payload['content'] = content
- if embeds:
- payload['embeds'] = embeds
- if allowed_mentions:
- payload['allowed_mentions'] = allowed_mentions
-
- form: List[Dict[str, Any]] = [
- {
- 'name': 'payload_json',
- 'value': utils._to_json(payload),
- }
- ]
-
- if file:
- form.append(
- {
- 'name': 'file',
- 'value': file.fp,
- 'filename': file.filename,
- 'content_type': 'application/octet-stream',
- }
- )
-
- return self.request(route, form=form, files=[file] if file else None)
-
- def create_interaction_response(
- self,
- interaction_id: Snowflake,
- token: str,
- *,
- type: InteractionResponseType,
- data: Optional[Dict[str, Any]] = None,
- ) -> Response[None]:
- r = Route(
- 'POST',
- '/interactions/{interaction_id}/{interaction_token}/callback',
- interaction_id=interaction_id,
- interaction_token=token,
- )
- payload: Dict[str, Any] = {
- 'type': type,
- }
-
- if data is not None:
- payload['data'] = data
-
- return self.request(r, json=payload)
-
- def get_original_interaction_response(
- self,
- application_id: Snowflake,
- token: str,
- ) -> Response[message.Message]:
- r = Route(
- 'GET',
- '/webhooks/{application_id}/{interaction_token}/messages/@original',
- application_id=application_id,
- interaction_token=token,
- )
- return self.request(r)
-
- def edit_original_interaction_response(
- self,
- application_id: Snowflake,
- token: str,
- file: Optional[File] = None,
- content: Optional[str] = None,
- embeds: Optional[List[embed.Embed]] = None,
- allowed_mentions: Optional[message.AllowedMentions] = None,
- ) -> Response[message.Message]:
- r = Route(
- 'PATCH',
- '/webhooks/{application_id}/{interaction_token}/messages/@original',
- application_id=application_id,
- interaction_token=token,
- )
- return self._edit_webhook_helper(r, file=file, content=content, embeds=embeds, allowed_mentions=allowed_mentions)
-
- def delete_original_interaction_response(self, application_id: Snowflake, token: str) -> Response[None]:
- r = Route(
- 'DELETE',
- '/webhooks/{application_id}/{interaction_token}/messages/@original',
- application_id=application_id,
- interaction_token=token,
- )
- return self.request(r)
-
- def create_followup_message(
- self,
- application_id: Snowflake,
- token: str,
- files: List[File] = [],
- content: Optional[str] = None,
- tts: bool = False,
- embeds: Optional[List[embed.Embed]] = None,
- allowed_mentions: Optional[message.AllowedMentions] = None,
- ) -> Response[message.Message]:
- r = Route(
- 'POST',
- '/webhooks/{application_id}/{interaction_token}',
- application_id=application_id,
- interaction_token=token,
- )
- return self.send_multipart_helper(
- r,
- content=content,
- files=files,
- tts=tts,
- embeds=embeds,
- allowed_mentions=allowed_mentions,
- )
-
- def edit_followup_message(
- self,
- application_id: Snowflake,
- token: str,
- message_id: Snowflake,
- file: Optional[File] = None,
- content: Optional[str] = None,
- embeds: Optional[List[embed.Embed]] = None,
- allowed_mentions: Optional[message.AllowedMentions] = None,
- ) -> Response[message.Message]:
- r = Route(
- 'PATCH',
- '/webhooks/{application_id}/{interaction_token}/messages/{message_id}',
- application_id=application_id,
- interaction_token=token,
- message_id=message_id,
- )
- return self._edit_webhook_helper(r, file=file, content=content, embeds=embeds, allowed_mentions=allowed_mentions)
-
- def delete_followup_message(self, application_id: Snowflake, token: str, message_id: Snowflake) -> Response[None]:
- r = Route(
- 'DELETE',
- '/webhooks/{application_id}/{interaction_token}/messages/{message_id}',
- application_id=application_id,
- interaction_token=token,
- message_id=message_id,
- )
- return self.request(r)
-
def get_guild_application_command_permissions(
self,
application_id: Snowflake,
diff --git a/discord/interactions.py b/discord/interactions.py
index b89d49f53..35d6c5982 100644
--- a/discord/interactions.py
+++ b/discord/interactions.py
@@ -38,7 +38,8 @@ from .member import Member
from .message import Message, Attachment
from .object import Object
from .permissions import Permissions
-from .webhook.async_ import async_context, Webhook, handle_message_parameters
+from .http import handle_message_parameters
+from .webhook.async_ import async_context, Webhook
__all__ = (
'Interaction',
diff --git a/discord/message.py b/discord/message.py
index c65d714b3..f56c5c45b 100644
--- a/discord/message.py
+++ b/discord/message.py
@@ -29,7 +29,21 @@ import datetime
import re
import io
from os import PathLike
-from typing import Dict, TYPE_CHECKING, Union, List, Optional, Any, Callable, Tuple, ClassVar, Optional, overload, TypeVar, Type
+from typing import (
+ Dict,
+ TYPE_CHECKING,
+ Union,
+ List,
+ Optional,
+ Any,
+ Callable,
+ Tuple,
+ ClassVar,
+ Optional,
+ overload,
+ TypeVar,
+ Type,
+)
from . import utils
from .reaction import Reaction
@@ -43,6 +57,7 @@ from .member import Member
from .flags import MessageFlags
from .file import File
from .utils import escape_mentions, MISSING
+from .http import handle_message_parameters
from .guild import Guild
from .mixins import Hashable
from .sticker import StickerItem
@@ -350,7 +365,7 @@ class DeletedReferencedMessage:
def id(self) -> int:
""":class:`int`: The message ID of the deleted referenced message."""
# the parent's message id won't be None here
- return self._parent.message_id # type: ignore
+ return self._parent.message_id # type: ignore
@property
def channel_id(self) -> int:
@@ -1217,6 +1232,8 @@ class Message(Hashable):
attachments: List[:class:`Attachment`]
A list of attachments to keep in the message. If ``[]`` is passed
then all attachments are removed.
+
+ .. versionadded:: 2.0
suppress: :class:`bool`
Whether to suppress embeds for the message. This removes
all the embeds if set to ``True``. If set to ``False``
@@ -1250,50 +1267,26 @@ class Message(Hashable):
You specified both ``embed`` and ``embeds``
"""
- payload: Dict[str, Any] = {}
- if content is not MISSING:
- if content is not None:
- payload['content'] = str(content)
- else:
- payload['content'] = None
-
- if embed is not MISSING and embeds is not MISSING:
- raise InvalidArgument('cannot pass both embed and embeds parameter to edit()')
-
- if embed is not MISSING:
- if embed is None:
- payload['embeds'] = []
- else:
- payload['embeds'] = [embed.to_dict()]
- elif embeds is not MISSING:
- payload['embeds'] = [e.to_dict() for e in embeds]
-
+ previous_allowed_mentions = self._state.allowed_mentions
if suppress is not MISSING:
flags = MessageFlags._from_value(self.flags.value)
- flags.suppress_embeds = suppress
- payload['flags'] = flags.value
-
- if allowed_mentions is MISSING:
- if self._state.allowed_mentions is not None and self.author.id == self._state.self_id:
- payload['allowed_mentions'] = self._state.allowed_mentions.to_dict()
else:
- if allowed_mentions is not None:
- if self._state.allowed_mentions is not None:
- payload['allowed_mentions'] = self._state.allowed_mentions.merge(allowed_mentions).to_dict()
- else:
- payload['allowed_mentions'] = allowed_mentions.to_dict()
-
- if attachments is not MISSING:
- payload['attachments'] = [a.to_dict() for a in attachments]
+ flags = MISSING
if view is not MISSING:
self._state.prevent_view_updates_for(self.id)
- if view:
- payload['components'] = view.to_components()
- else:
- payload['components'] = []
- data = await self._state.http.edit_message(self.channel.id, self.id, **payload)
+ params = handle_message_parameters(
+ content=content,
+ flags=flags,
+ embed=embed,
+ embeds=embeds,
+ attachments=attachments,
+ view=view,
+ allowed_mentions=allowed_mentions,
+ previous_allowed_mentions=previous_allowed_mentions,
+ )
+ data = await self._state.http.edit_message(self.channel.id, self.id, params=params)
message = Message(state=self._state, channel=self.channel, data=data)
if view and not view.is_finished():
diff --git a/discord/webhook/async_.py b/discord/webhook/async_.py
index be58a93ac..77bd82e17 100644
--- a/discord/webhook/async_.py
+++ b/discord/webhook/async_.py
@@ -41,8 +41,9 @@ from ..errors import InvalidArgument, HTTPException, Forbidden, NotFound, Discor
from ..message import Message
from ..enums import try_enum, WebhookType
from ..user import BaseUser, User
+from ..flags import MessageFlags
from ..asset import Asset
-from ..http import Route
+from ..http import Route, handle_message_parameters
from ..mixins import Hashable
from ..channel import PartialMessageable
@@ -416,107 +417,6 @@ class AsyncWebhookAdapter:
return self.request(r, session=session)
-class ExecuteWebhookParameters(NamedTuple):
- payload: Optional[Dict[str, Any]]
- multipart: Optional[List[Dict[str, Any]]]
- files: Optional[List[File]]
-
-
-def handle_message_parameters(
- content: Optional[str] = MISSING,
- *,
- username: str = MISSING,
- avatar_url: Any = MISSING,
- tts: bool = False,
- ephemeral: bool = False,
- file: File = MISSING,
- files: List[File] = MISSING,
- embed: Optional[Embed] = MISSING,
- embeds: List[Embed] = MISSING,
- view: Optional[View] = MISSING,
- allowed_mentions: Optional[AllowedMentions] = MISSING,
- previous_allowed_mentions: Optional[AllowedMentions] = None,
-) -> ExecuteWebhookParameters:
- if files is not MISSING and file is not MISSING:
- raise TypeError('Cannot mix file and files keyword arguments.')
- if embeds is not MISSING and embed is not MISSING:
- raise TypeError('Cannot mix embed and embeds keyword arguments.')
-
- payload = {}
- if embeds is not MISSING:
- if len(embeds) > 10:
- raise InvalidArgument('embeds has a maximum of 10 elements.')
- payload['embeds'] = [e.to_dict() for e in embeds]
-
- if embed is not MISSING:
- if embed is None:
- payload['embeds'] = []
- else:
- payload['embeds'] = [embed.to_dict()]
-
- if content is not MISSING:
- if content is not None:
- payload['content'] = str(content)
- else:
- payload['content'] = None
-
- if view is not MISSING:
- if view is not None:
- payload['components'] = view.to_components()
- else:
- payload['components'] = []
-
- payload['tts'] = tts
- if avatar_url:
- payload['avatar_url'] = str(avatar_url)
- if username:
- payload['username'] = username
- if ephemeral:
- payload['flags'] = 64
-
- if allowed_mentions:
- if previous_allowed_mentions is not None:
- payload['allowed_mentions'] = previous_allowed_mentions.merge(allowed_mentions).to_dict()
- else:
- payload['allowed_mentions'] = allowed_mentions.to_dict()
- elif previous_allowed_mentions is not None:
- payload['allowed_mentions'] = previous_allowed_mentions.to_dict()
-
- multipart = []
- if file is not MISSING:
- files = [file]
-
- if files:
- for index, file in enumerate(files):
- attachments = []
- for index, file in enumerate(files):
- attachment = {
- "id": index,
- "filename": file.filename,
- }
-
- if file.description is not None:
- attachment["description"] = file.description
-
- attachments.append(attachment)
-
- payload['attachments'] = attachments
-
- multipart.append({'name': 'payload_json', 'value': utils._to_json(payload)})
- payload = None
- for index, file in enumerate(files):
- multipart.append(
- {
- 'name': f'files[{index}]',
- 'value': file.fp,
- 'filename': file.filename,
- 'content_type': 'application/octet-stream',
- }
- )
-
- return ExecuteWebhookParameters(payload=payload, multipart=multipart, files=files)
-
-
async_context: ContextVar[AsyncWebhookAdapter] = ContextVar('async_webhook_context', default=AsyncWebhookAdapter())
@@ -1356,6 +1256,10 @@ class Webhook(BaseWebhook):
previous_mentions: Optional[AllowedMentions] = getattr(self._state, 'allowed_mentions', None)
if content is None:
content = MISSING
+ if ephemeral:
+ flags = MessageFlags._from_value(64)
+ else:
+ flags = MISSING
application_webhook = self.type is WebhookType.application
if ephemeral and not application_webhook:
@@ -1379,7 +1283,7 @@ class Webhook(BaseWebhook):
files=files,
embed=embed,
embeds=embeds,
- ephemeral=ephemeral,
+ flags=flags,
view=view,
allowed_mentions=allowed_mentions,
previous_allowed_mentions=previous_mentions,
diff --git a/discord/webhook/sync.py b/discord/webhook/sync.py
index 3f7cd6018..bf79c2c1b 100644
--- a/discord/webhook/sync.py
+++ b/discord/webhook/sync.py
@@ -43,10 +43,10 @@ import weakref
from .. import utils
from ..errors import InvalidArgument, HTTPException, Forbidden, NotFound, DiscordServerError
from ..message import Message
-from ..http import Route
+from ..http import Route, handle_message_parameters
from ..channel import PartialMessageable
-from .async_ import BaseWebhook, handle_message_parameters, _WebhookState
+from .async_ import BaseWebhook, _WebhookState
__all__ = (
'SyncWebhook',