Browse Source

Add support for editing message attachments

pull/7494/head
Josh 3 years ago
committed by GitHub
parent
commit
dede5539ee
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 13
      discord/file.py
  2. 53
      discord/http.py
  3. 105
      discord/interactions.py
  4. 68
      discord/message.py
  5. 138
      discord/webhook/async_.py
  6. 89
      discord/webhook/sync.py

13
discord/file.py

@ -23,7 +23,7 @@ DEALINGS IN THE SOFTWARE.
""" """
from __future__ import annotations from __future__ import annotations
from typing import Optional, Union from typing import Any, Dict, Optional, Union
import os import os
import io import io
@ -126,3 +126,14 @@ class File:
self.fp.close = self._closer self.fp.close = self._closer
if self._owner: if self._owner:
self._closer() self._closer()
def to_dict(self, index: int) -> Dict[str, Any]:
payload = {
'id': index,
'filename': self.filename,
}
if self.description is not None:
payload['description'] = self.description
return payload

53
discord/http.py

@ -52,13 +52,13 @@ import aiohttp
from .errors import HTTPException, Forbidden, NotFound, LoginFailure, DiscordServerError, GatewayNotFound, InvalidArgument from .errors import HTTPException, Forbidden, NotFound, LoginFailure, DiscordServerError, GatewayNotFound, InvalidArgument
from .gateway import DiscordClientWebSocketResponse from .gateway import DiscordClientWebSocketResponse
from .file import File
from . import __version__, utils from . import __version__, utils
from .utils import MISSING from .utils import MISSING
_log = logging.getLogger(__name__) _log = logging.getLogger(__name__)
if TYPE_CHECKING: if TYPE_CHECKING:
from .file import File
from .ui.view import View from .ui.view import View
from .embeds import Embed from .embeds import Embed
from .mentions import AllowedMentions from .mentions import AllowedMentions
@ -147,7 +147,7 @@ def handle_message_parameters(
files: List[File] = MISSING, files: List[File] = MISSING,
embed: Optional[Embed] = MISSING, embed: Optional[Embed] = MISSING,
embeds: List[Embed] = MISSING, embeds: List[Embed] = MISSING,
attachments: List[Attachment] = MISSING, attachments: List[Union[Attachment, File]] = MISSING,
view: Optional[View] = MISSING, view: Optional[View] = MISSING,
allowed_mentions: Optional[AllowedMentions] = MISSING, allowed_mentions: Optional[AllowedMentions] = MISSING,
message_reference: Optional[message.MessageReference] = MISSING, message_reference: Optional[message.MessageReference] = MISSING,
@ -160,6 +160,12 @@ def handle_message_parameters(
if embeds is not MISSING and embed is not MISSING: if embeds is not MISSING and embed is not MISSING:
raise TypeError('Cannot mix embed and embeds keyword arguments.') raise TypeError('Cannot mix embed and embeds keyword arguments.')
if file is not MISSING:
files = [file]
if attachments is not MISSING and files is not MISSING:
raise TypeError('Cannot mix attachments and files keyword arguments.')
payload = {} payload = {}
if embeds is not MISSING: if embeds is not MISSING:
if len(embeds) > 10: if len(embeds) > 10:
@ -190,11 +196,6 @@ def handle_message_parameters(
if message_reference is not MISSING: if message_reference is not MISSING:
payload['message_reference'] = message_reference 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 MISSING:
if stickers is not None: if stickers is not None:
payload['sticker_ids'] = stickers payload['sticker_ids'] = stickers
@ -224,26 +225,25 @@ def handle_message_parameters(
except KeyError: except KeyError:
pass pass
multipart = [] if attachments is MISSING:
if file is not MISSING: attachments = files # type: ignore
files = [file] else:
files = [a for a in attachments if isinstance(a, File)]
if files: if attachments is not MISSING:
for index, file in enumerate(files): file_index = 0
attachments_payload = [] attachments_payload = []
for index, file in enumerate(files): for attachment in attachments:
attachment = { if isinstance(attachment, File):
'id': index, attachments_payload.append(attachment.to_dict(file_index))
'filename': file.filename, file_index += 1
} else:
attachments_payload.append(attachment.to_dict())
if file.description is not None:
attachment['description'] = file.description
attachments_payload.append(attachment)
payload['attachments'] = attachments_payload payload['attachments'] = attachments_payload
multipart = []
if files:
multipart.append({'name': 'payload_json', 'value': utils._to_json(payload)}) multipart.append({'name': 'payload_json', 'value': utils._to_json(payload)})
payload = None payload = None
for index, file in enumerate(files): for index, file in enumerate(files):
@ -596,7 +596,10 @@ class HTTPClient:
def edit_message(self, channel_id: Snowflake, message_id: Snowflake, *, params: MultipartParameters) -> 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) r = Route('PATCH', '/channels/{channel_id}/messages/{message_id}', channel_id=channel_id, message_id=message_id)
return self.request(r, json=params.payload) if params.files:
return self.request(r, files=params.files, form=params.multipart)
else:
return self.request(r, json=params.payload)
def add_reaction(self, channel_id: Snowflake, message_id: Snowflake, emoji: str) -> Response[None]: def add_reaction(self, channel_id: Snowflake, message_id: Snowflake, emoji: str) -> Response[None]:
r = Route( r = Route(

105
discord/interactions.py

@ -259,8 +259,7 @@ class Interaction:
content: Optional[str] = MISSING, content: Optional[str] = MISSING,
embeds: List[Embed] = MISSING, embeds: List[Embed] = MISSING,
embed: Optional[Embed] = MISSING, embed: Optional[Embed] = MISSING,
file: File = MISSING, attachments: List[Union[Attachment, File]] = MISSING,
files: List[File] = MISSING,
view: Optional[View] = MISSING, view: Optional[View] = MISSING,
allowed_mentions: Optional[AllowedMentions] = None, allowed_mentions: Optional[AllowedMentions] = None,
) -> InteractionMessage: ) -> InteractionMessage:
@ -283,11 +282,14 @@ class Interaction:
embed: Optional[:class:`Embed`] embed: Optional[:class:`Embed`]
The embed to edit the message with. ``None`` suppresses the embeds. The embed to edit the message with. ``None`` suppresses the embeds.
This should not be mixed with the ``embeds`` parameter. This should not be mixed with the ``embeds`` parameter.
file: :class:`File` attachments: List[Union[:class:`Attachment`, :class:`File`]]
The file to upload. This cannot be mixed with ``files`` parameter. A list of attachments to keep in the message as well as new files to upload. If ``[]`` is passed
files: List[:class:`File`] then all attachments are removed.
A list of files to send with the content. This cannot be mixed with the
``file`` parameter. .. note::
New files will always appear after current attachments.
allowed_mentions: :class:`AllowedMentions` allowed_mentions: :class:`AllowedMentions`
Controls the mentions being processed in this message. Controls the mentions being processed in this message.
See :meth:`.abc.Messageable.send` for more information. See :meth:`.abc.Messageable.send` for more information.
@ -302,7 +304,7 @@ class Interaction:
Forbidden Forbidden
Edited a message that is not yours. Edited a message that is not yours.
TypeError TypeError
You specified both ``embed`` and ``embeds`` or ``file`` and ``files`` You specified both ``embed`` and ``embeds``
ValueError ValueError
The length of ``embeds`` was invalid. The length of ``embeds`` was invalid.
@ -315,8 +317,7 @@ class Interaction:
previous_mentions: Optional[AllowedMentions] = self._state.allowed_mentions previous_mentions: Optional[AllowedMentions] = self._state.allowed_mentions
params = handle_message_parameters( params = handle_message_parameters(
content=content, content=content,
file=file, attachments=attachments,
files=files,
embed=embed, embed=embed,
embeds=embeds, embeds=embeds,
view=view, view=view,
@ -549,7 +550,7 @@ class InteractionResponse:
content: Optional[Any] = MISSING, content: Optional[Any] = MISSING,
embed: Optional[Embed] = MISSING, embed: Optional[Embed] = MISSING,
embeds: List[Embed] = MISSING, embeds: List[Embed] = MISSING,
attachments: List[Attachment] = MISSING, attachments: List[Union[Attachment, File]] = MISSING,
view: Optional[View] = MISSING, view: Optional[View] = MISSING,
allowed_mentions: Optional[AllowedMentions] = MISSING, allowed_mentions: Optional[AllowedMentions] = MISSING,
) -> None: ) -> None:
@ -567,9 +568,14 @@ class InteractionResponse:
embed: Optional[:class:`Embed`] embed: Optional[:class:`Embed`]
The embed to edit the message with. ``None`` suppresses the embeds. The embed to edit the message with. ``None`` suppresses the embeds.
This should not be mixed with the ``embeds`` parameter. This should not be mixed with the ``embeds`` parameter.
attachments: List[:class:`Attachment`] attachments: List[Union[:class:`Attachment`, :class:`File`]]
A list of attachments to keep in the message. If ``[]`` is passed A list of attachments to keep in the message as well as new files to upload. If ``[]`` is passed
then all attachments are removed. then all attachments are removed.
.. note::
New files will always appear after current attachments.
view: Optional[:class:`~discord.ui.View`] view: Optional[:class:`~discord.ui.View`]
The updated view to update this message with. If ``None`` is passed then The updated view to update this message with. If ``None`` is passed then
the view is removed. the view is removed.
@ -667,8 +673,7 @@ class InteractionMessage(Message):
content: Optional[str] = MISSING, content: Optional[str] = MISSING,
embeds: List[Embed] = MISSING, embeds: List[Embed] = MISSING,
embed: Optional[Embed] = MISSING, embed: Optional[Embed] = MISSING,
file: File = MISSING, attachments: List[Union[Attachment, File]] = MISSING,
files: List[File] = MISSING,
view: Optional[View] = MISSING, view: Optional[View] = MISSING,
allowed_mentions: Optional[AllowedMentions] = None, allowed_mentions: Optional[AllowedMentions] = None,
) -> InteractionMessage: ) -> InteractionMessage:
@ -685,11 +690,14 @@ class InteractionMessage(Message):
embed: Optional[:class:`Embed`] embed: Optional[:class:`Embed`]
The embed to edit the message with. ``None`` suppresses the embeds. The embed to edit the message with. ``None`` suppresses the embeds.
This should not be mixed with the ``embeds`` parameter. This should not be mixed with the ``embeds`` parameter.
file: :class:`File` attachments: List[Union[:class:`Attachment`, :class:`File`]]
The file to upload. This cannot be mixed with ``files`` parameter. A list of attachments to keep in the message as well as new files to upload. If ``[]`` is passed
files: List[:class:`File`] then all attachments are removed.
A list of files to send with the content. This cannot be mixed with the
``file`` parameter. .. note::
New files will always appear after current attachments.
allowed_mentions: :class:`AllowedMentions` allowed_mentions: :class:`AllowedMentions`
Controls the mentions being processed in this message. Controls the mentions being processed in this message.
See :meth:`.abc.Messageable.send` for more information. See :meth:`.abc.Messageable.send` for more information.
@ -704,7 +712,7 @@ class InteractionMessage(Message):
Forbidden Forbidden
Edited a message that is not yours. Edited a message that is not yours.
TypeError TypeError
You specified both ``embed`` and ``embeds`` or ``file`` and ``files`` You specified both ``embed`` and ``embeds``
ValueError ValueError
The length of ``embeds`` was invalid. The length of ``embeds`` was invalid.
@ -717,11 +725,62 @@ class InteractionMessage(Message):
content=content, content=content,
embeds=embeds, embeds=embeds,
embed=embed, embed=embed,
file=file, attachments=attachments,
files=files,
view=view, view=view,
allowed_mentions=allowed_mentions, allowed_mentions=allowed_mentions,
) )
async def add_files(self, *files: File) -> InteractionMessage:
r"""|coro|
Adds new files to the end of the message attachments.
.. versionadded:: 2.0
Parameters
-----------
\*files: :class:`File`
New files to add to the message.
Raises
-------
HTTPException
Editing the message failed.
Forbidden
Tried to edit a message that isn't yours.
Returns
---------
:class:`InteractionMessage`
The newly edited message.
"""
return await self.edit(attachments=[*self.attachments, *files])
async def remove_attachments(self, *attachments: Attachment) -> InteractionMessage:
r"""|coro|
Removes attachments from the message.
.. versionadded:: 2.0
Parameters
-----------
\*attachments: :class:`Attachment`
Attachments to remove from the message.
Raises
-------
HTTPException
Editing the message failed.
Forbidden
Tried to edit a message that isn't yours.
Returns
---------
:class:`InteractionMessage`
The newly edited message.
"""
return await self.edit(attachments=[a for a in self.attachments if a not in attachments])
async def delete(self, *, delay: Optional[float] = None) -> None: async def delete(self, *, delay: Optional[float] = None) -> None:
"""|coro| """|coro|

68
discord/message.py

@ -1176,7 +1176,7 @@ class Message(Hashable):
*, *,
content: Optional[str] = ..., content: Optional[str] = ...,
embed: Optional[Embed] = ..., embed: Optional[Embed] = ...,
attachments: List[Attachment] = ..., attachments: List[Union[Attachment, File]] = ...,
suppress: bool = ..., suppress: bool = ...,
delete_after: Optional[float] = ..., delete_after: Optional[float] = ...,
allowed_mentions: Optional[AllowedMentions] = ..., allowed_mentions: Optional[AllowedMentions] = ...,
@ -1190,7 +1190,7 @@ class Message(Hashable):
*, *,
content: Optional[str] = ..., content: Optional[str] = ...,
embeds: List[Embed] = ..., embeds: List[Embed] = ...,
attachments: List[Attachment] = ..., attachments: List[Union[Attachment, File]] = ...,
suppress: bool = ..., suppress: bool = ...,
delete_after: Optional[float] = ..., delete_after: Optional[float] = ...,
allowed_mentions: Optional[AllowedMentions] = ..., allowed_mentions: Optional[AllowedMentions] = ...,
@ -1203,7 +1203,7 @@ class Message(Hashable):
content: Optional[str] = MISSING, content: Optional[str] = MISSING,
embed: Optional[Embed] = MISSING, embed: Optional[Embed] = MISSING,
embeds: List[Embed] = MISSING, embeds: List[Embed] = MISSING,
attachments: List[Attachment] = MISSING, attachments: List[Union[Attachment, File]] = MISSING,
suppress: bool = MISSING, suppress: bool = MISSING,
delete_after: Optional[float] = None, delete_after: Optional[float] = None,
allowed_mentions: Optional[AllowedMentions] = MISSING, allowed_mentions: Optional[AllowedMentions] = MISSING,
@ -1231,10 +1231,14 @@ class Message(Hashable):
To remove all embeds ``[]`` should be passed. To remove all embeds ``[]`` should be passed.
.. versionadded:: 2.0 .. versionadded:: 2.0
attachments: List[:class:`Attachment`] attachments: List[Union[:class:`Attachment`, :class:`File`]]
A list of attachments to keep in the message. If ``[]`` is passed A list of attachments to keep in the message as well as new files to upload. If ``[]`` is passed
then all attachments are removed. then all attachments are removed.
.. note::
New files will always appear after current attachments.
.. versionadded:: 2.0 .. versionadded:: 2.0
suppress: :class:`bool` suppress: :class:`bool`
Whether to suppress embeds for the message. This removes Whether to suppress embeds for the message. This removes
@ -1299,6 +1303,58 @@ class Message(Hashable):
return message return message
async def add_files(self, *files: File) -> Message:
r"""|coro|
Adds new files to the end of the message attachments.
.. versionadded:: 2.0
Parameters
-----------
\*files: :class:`File`
New files to add to the message.
Raises
-------
HTTPException
Editing the message failed.
Forbidden
Tried to edit a message that isn't yours.
Returns
--------
:class:`Message`
The newly edited message.
"""
return await self.edit(attachments=[*self.attachments, *files])
async def remove_attachments(self, *attachments: Attachment) -> Message:
r"""|coro|
Removes attachments from the message.
.. versionadded:: 2.0
Parameters
-----------
\*attachments: :class:`Attachment`
Attachments to remove from the message.
Raises
-------
HTTPException
Editing the message failed.
Forbidden
Tried to edit a message that isn't yours.
Returns
--------
:class:`Message`
The newly edited message.
"""
return await self.edit(attachments=[a for a in self.attachments if a not in attachments])
async def publish(self) -> None: async def publish(self) -> None:
"""|coro| """|coro|
@ -1643,6 +1699,8 @@ class PartialMessage(Hashable):
jump_url: str = Message.jump_url # type: ignore jump_url: str = Message.jump_url # type: ignore
edit = Message.edit edit = Message.edit
add_files = Message.add_files
remove_attachments = Message.remove_attachments
delete = Message.delete delete = Message.delete
publish = Message.publish publish = Message.publish
pin = Message.pin pin = Message.pin

138
discord/webhook/async_.py

@ -30,7 +30,7 @@ import json
import re import re
from urllib.parse import quote as urlquote from urllib.parse import quote as urlquote
from typing import Any, Dict, List, Literal, NamedTuple, Optional, TYPE_CHECKING, Tuple, Union, overload from typing import Any, Dict, List, Literal, Optional, TYPE_CHECKING, Tuple, Union, overload
from contextvars import ContextVar from contextvars import ContextVar
import weakref import weakref
@ -434,7 +434,7 @@ def interaction_message_response_params(
files: List[File] = MISSING, files: List[File] = MISSING,
embed: Optional[Embed] = MISSING, embed: Optional[Embed] = MISSING,
embeds: List[Embed] = MISSING, embeds: List[Embed] = MISSING,
attachments: List[Attachment] = MISSING, attachments: List[Union[Attachment, File]] = MISSING,
view: Optional[View] = MISSING, view: Optional[View] = MISSING,
allowed_mentions: Optional[AllowedMentions] = MISSING, allowed_mentions: Optional[AllowedMentions] = MISSING,
previous_allowed_mentions: Optional[AllowedMentions] = None, previous_allowed_mentions: Optional[AllowedMentions] = None,
@ -444,6 +444,12 @@ def interaction_message_response_params(
if embeds is not MISSING and embed is not MISSING: if embeds is not MISSING and embed is not MISSING:
raise TypeError('Cannot mix embed and embeds keyword arguments.') raise TypeError('Cannot mix embed and embeds keyword arguments.')
if file is not MISSING:
files = [file]
if attachments is not MISSING and files is not MISSING:
raise TypeError('Cannot mix attachments and files keyword arguments.')
data: Optional[Dict[str, Any]] = { data: Optional[Dict[str, Any]] = {
'tts': tts, 'tts': tts,
} }
@ -471,11 +477,6 @@ def interaction_message_response_params(
else: else:
data['components'] = [] data['components'] = []
if attachments is not MISSING:
# Note: This will be overwritten if file or files is provided
# However, right now this is only passed via edit not send
data['attachments'] = [a.to_dict() for a in attachments]
if flags is not MISSING: if flags is not MISSING:
data['flags'] = flags.value data['flags'] = flags.value
@ -487,26 +488,25 @@ def interaction_message_response_params(
elif previous_allowed_mentions is not None: elif previous_allowed_mentions is not None:
data['allowed_mentions'] = previous_allowed_mentions.to_dict() data['allowed_mentions'] = previous_allowed_mentions.to_dict()
multipart = [] if attachments is MISSING:
if file is not MISSING: attachments = files # type: ignore
files = [file] else:
files = [a for a in attachments if isinstance(a, 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) if attachments is not MISSING:
file_index = 0
attachments_payload = []
for attachment in attachments:
if isinstance(attachment, File):
attachments_payload.append(attachment.to_dict(file_index))
file_index += 1
else:
attachments_payload.append(attachment.to_dict())
data['attachments'] = attachments_payload data['attachments'] = attachments_payload
multipart = []
if files:
data = {'type': type, 'data': data} data = {'type': type, 'data': data}
multipart.append({'name': 'payload_json', 'value': utils._to_json(data)}) multipart.append({'name': 'payload_json', 'value': utils._to_json(data)})
data = None data = None
@ -656,8 +656,7 @@ class WebhookMessage(Message):
content: Optional[str] = MISSING, content: Optional[str] = MISSING,
embeds: List[Embed] = MISSING, embeds: List[Embed] = MISSING,
embed: Optional[Embed] = MISSING, embed: Optional[Embed] = MISSING,
file: File = MISSING, attachments: List[Union[Attachment, File]] = MISSING,
files: List[File] = MISSING,
view: Optional[View] = MISSING, view: Optional[View] = MISSING,
allowed_mentions: Optional[AllowedMentions] = None, allowed_mentions: Optional[AllowedMentions] = None,
) -> WebhookMessage: ) -> WebhookMessage:
@ -679,13 +678,13 @@ class WebhookMessage(Message):
embed: Optional[:class:`Embed`] embed: Optional[:class:`Embed`]
The embed to edit the message with. ``None`` suppresses the embeds. The embed to edit the message with. ``None`` suppresses the embeds.
This should not be mixed with the ``embeds`` parameter. This should not be mixed with the ``embeds`` parameter.
file: :class:`File` attachments: List[Union[:class:`Attachment`, :class:`File`]]
The file to upload. This cannot be mixed with ``files`` parameter. A list of attachments to keep in the message as well as new files to upload. If ``[]`` is passed
then all attachments are removed.
.. note::
.. versionadded:: 2.0 New files will always appear after current attachments.
files: List[:class:`File`]
A list of files to send with the content. This cannot be mixed with the
``file`` parameter.
.. versionadded:: 2.0 .. versionadded:: 2.0
allowed_mentions: :class:`AllowedMentions` allowed_mentions: :class:`AllowedMentions`
@ -704,7 +703,7 @@ class WebhookMessage(Message):
Forbidden Forbidden
Edited a message that is not yours. Edited a message that is not yours.
TypeError TypeError
You specified both ``embed`` and ``embeds`` or ``file`` and ``files`` You specified both ``embed`` and ``embeds``
ValueError ValueError
The length of ``embeds`` was invalid The length of ``embeds`` was invalid
InvalidArgument InvalidArgument
@ -720,12 +719,63 @@ class WebhookMessage(Message):
content=content, content=content,
embeds=embeds, embeds=embeds,
embed=embed, embed=embed,
file=file, attachments=attachments,
files=files,
view=view, view=view,
allowed_mentions=allowed_mentions, allowed_mentions=allowed_mentions,
) )
async def add_files(self, *files: File) -> WebhookMessage:
r"""|coro|
Adds new files to the end of the message attachments.
.. versionadded:: 2.0
Parameters
-----------
\*files: :class:`File`
New files to add to the message.
Raises
-------
HTTPException
Editing the message failed.
Forbidden
Tried to edit a message that isn't yours.
Returns
--------
:class:`WebhookMessage`
The newly edited message.
"""
return await self.edit(attachments=[*self.attachments, *files])
async def remove_attachments(self, *attachments: Attachment) -> WebhookMessage:
r"""|coro|
Removes attachments from the message.
.. versionadded:: 2.0
Parameters
-----------
\*attachments: :class:`Attachment`
Attachments to remove from the message.
Raises
-------
HTTPException
Editing the message failed.
Forbidden
Tried to edit a message that isn't yours.
Returns
--------
:class:`WebhookMessage`
The newly edited message.
"""
return await self.edit(attachments=[a for a in self.attachments if a not in attachments])
async def delete(self, *, delay: Optional[float] = None) -> None: async def delete(self, *, delay: Optional[float] = None) -> None:
"""|coro| """|coro|
@ -1470,8 +1520,7 @@ class Webhook(BaseWebhook):
content: Optional[str] = MISSING, content: Optional[str] = MISSING,
embeds: List[Embed] = MISSING, embeds: List[Embed] = MISSING,
embed: Optional[Embed] = MISSING, embed: Optional[Embed] = MISSING,
file: File = MISSING, attachments: List[Union[Attachment, File]] = MISSING,
files: List[File] = MISSING,
view: Optional[View] = MISSING, view: Optional[View] = MISSING,
allowed_mentions: Optional[AllowedMentions] = None, allowed_mentions: Optional[AllowedMentions] = None,
) -> WebhookMessage: ) -> WebhookMessage:
@ -1498,13 +1547,9 @@ class Webhook(BaseWebhook):
embed: Optional[:class:`Embed`] embed: Optional[:class:`Embed`]
The embed to edit the message with. ``None`` suppresses the embeds. The embed to edit the message with. ``None`` suppresses the embeds.
This should not be mixed with the ``embeds`` parameter. This should not be mixed with the ``embeds`` parameter.
file: :class:`File` attachments: List[Union[:class:`Attachment`, :class:`File`]]
The file to upload. This cannot be mixed with ``files`` parameter. A list of attachments to keep in the message as well as new files to upload. If ``[]`` is passed
then all attachments are removed.
.. versionadded:: 2.0
files: List[:class:`File`]
A list of files to send with the content. This cannot be mixed with the
``file`` parameter.
.. versionadded:: 2.0 .. versionadded:: 2.0
allowed_mentions: :class:`AllowedMentions` allowed_mentions: :class:`AllowedMentions`
@ -1524,7 +1569,7 @@ class Webhook(BaseWebhook):
Forbidden Forbidden
Edited a message that is not yours. Edited a message that is not yours.
TypeError TypeError
You specified both ``embed`` and ``embeds`` or ``file`` and ``files`` You specified both ``embed`` and ``embeds``
ValueError ValueError
The length of ``embeds`` was invalid The length of ``embeds`` was invalid
InvalidArgument InvalidArgument
@ -1549,8 +1594,7 @@ class Webhook(BaseWebhook):
previous_mentions: Optional[AllowedMentions] = getattr(self._state, 'allowed_mentions', None) previous_mentions: Optional[AllowedMentions] = getattr(self._state, 'allowed_mentions', None)
params = handle_message_parameters( params = handle_message_parameters(
content=content, content=content,
file=file, attachments=attachments,
files=files,
embed=embed, embed=embed,
embeds=embeds, embeds=embeds,
view=view, view=view,

89
discord/webhook/sync.py

@ -59,6 +59,7 @@ if TYPE_CHECKING:
from ..file import File from ..file import File
from ..embeds import Embed from ..embeds import Embed
from ..mentions import AllowedMentions from ..mentions import AllowedMentions
from ..message import Attachment
from ..types.webhook import ( from ..types.webhook import (
Webhook as WebhookPayload, Webhook as WebhookPayload,
) )
@ -381,8 +382,7 @@ class SyncWebhookMessage(Message):
content: Optional[str] = MISSING, content: Optional[str] = MISSING,
embeds: List[Embed] = MISSING, embeds: List[Embed] = MISSING,
embed: Optional[Embed] = MISSING, embed: Optional[Embed] = MISSING,
file: File = MISSING, attachments: List[Union[Attachment, File]] = MISSING,
files: List[File] = MISSING,
allowed_mentions: Optional[AllowedMentions] = None, allowed_mentions: Optional[AllowedMentions] = None,
) -> SyncWebhookMessage: ) -> SyncWebhookMessage:
"""Edits the message. """Edits the message.
@ -396,11 +396,15 @@ class SyncWebhookMessage(Message):
embed: Optional[:class:`Embed`] embed: Optional[:class:`Embed`]
The embed to edit the message with. ``None`` suppresses the embeds. The embed to edit the message with. ``None`` suppresses the embeds.
This should not be mixed with the ``embeds`` parameter. This should not be mixed with the ``embeds`` parameter.
file: :class:`File` attachments: List[Union[:class:`Attachment`, :class:`File`]]
The file to upload. This cannot be mixed with ``files`` parameter. A list of attachments to keep in the message as well as new files to upload. If ``[]`` is passed
files: List[:class:`File`] then all attachments are removed.
A list of files to send with the content. This cannot be mixed with the
``file`` parameter. .. note::
New files will always appear after current attachments.
.. versionadded:: 2.0
allowed_mentions: :class:`AllowedMentions` allowed_mentions: :class:`AllowedMentions`
Controls the mentions being processed in this message. Controls the mentions being processed in this message.
See :meth:`.abc.Messageable.send` for more information. See :meth:`.abc.Messageable.send` for more information.
@ -412,7 +416,7 @@ class SyncWebhookMessage(Message):
Forbidden Forbidden
Edited a message that is not yours. Edited a message that is not yours.
TypeError TypeError
You specified both ``embed`` and ``embeds`` or ``file`` and ``files`` You specified both ``embed`` and ``embeds``
ValueError ValueError
The length of ``embeds`` was invalid The length of ``embeds`` was invalid
InvalidArgument InvalidArgument
@ -428,11 +432,58 @@ class SyncWebhookMessage(Message):
content=content, content=content,
embeds=embeds, embeds=embeds,
embed=embed, embed=embed,
file=file, attachments=attachments,
files=files,
allowed_mentions=allowed_mentions, allowed_mentions=allowed_mentions,
) )
def add_files(self, *files: File) -> SyncWebhookMessage:
r"""Adds new files to the end of the message attachments.
.. versionadded:: 2.0
Parameters
-----------
\*files: :class:`File`
New files to add to the message.
Raises
-------
HTTPException
Editing the message failed.
Forbidden
Tried to edit a message that isn't yours.
Returns
--------
:class:`SyncWebhookMessage`
The newly edited message.
"""
return self.edit(attachments=[*self.attachments, *files])
def remove_attachments(self, *attachments: Attachment) -> SyncWebhookMessage:
r"""Removes attachments from the message.
.. versionadded:: 2.0
Parameters
-----------
\*attachments: :class:`Attachment`
Attachments to remove from the message.
Raises
-------
HTTPException
Editing the message failed.
Forbidden
Tried to edit a message that isn't yours.
Returns
--------
:class:`SyncWebhookMessage`
The newly edited message.
"""
return self.edit(attachments=[a for a in self.attachments if a not in attachments])
def delete(self, *, delay: Optional[float] = None) -> None: def delete(self, *, delay: Optional[float] = None) -> None:
"""Deletes the message. """Deletes the message.
@ -966,8 +1017,7 @@ class SyncWebhook(BaseWebhook):
content: Optional[str] = MISSING, content: Optional[str] = MISSING,
embeds: List[Embed] = MISSING, embeds: List[Embed] = MISSING,
embed: Optional[Embed] = MISSING, embed: Optional[Embed] = MISSING,
file: File = MISSING, attachments: List[Union[Attachment, File]] = MISSING,
files: List[File] = MISSING,
allowed_mentions: Optional[AllowedMentions] = None, allowed_mentions: Optional[AllowedMentions] = None,
) -> SyncWebhookMessage: ) -> SyncWebhookMessage:
"""Edits a message owned by this webhook. """Edits a message owned by this webhook.
@ -988,11 +1038,11 @@ class SyncWebhook(BaseWebhook):
embed: Optional[:class:`Embed`] embed: Optional[:class:`Embed`]
The embed to edit the message with. ``None`` suppresses the embeds. The embed to edit the message with. ``None`` suppresses the embeds.
This should not be mixed with the ``embeds`` parameter. This should not be mixed with the ``embeds`` parameter.
file: :class:`File` attachments: List[Union[:class:`Attachment`, :class:`File`]]
The file to upload. This cannot be mixed with ``files`` parameter. A list of attachments to keep in the message as well as new files to upload. If ``[]`` is passed
files: List[:class:`File`] then all attachments are removed.
A list of files to send with the content. This cannot be mixed with the
``file`` parameter. .. versionadded:: 2.0
allowed_mentions: :class:`AllowedMentions` allowed_mentions: :class:`AllowedMentions`
Controls the mentions being processed in this message. Controls the mentions being processed in this message.
See :meth:`.abc.Messageable.send` for more information. See :meth:`.abc.Messageable.send` for more information.
@ -1004,7 +1054,7 @@ class SyncWebhook(BaseWebhook):
Forbidden Forbidden
Edited a message that is not yours. Edited a message that is not yours.
TypeError TypeError
You specified both ``embed`` and ``embeds`` or ``file`` and ``files`` You specified both ``embed`` and ``embeds``
ValueError ValueError
The length of ``embeds`` was invalid The length of ``embeds`` was invalid
InvalidArgument InvalidArgument
@ -1017,8 +1067,7 @@ class SyncWebhook(BaseWebhook):
previous_mentions: Optional[AllowedMentions] = getattr(self._state, 'allowed_mentions', None) previous_mentions: Optional[AllowedMentions] = getattr(self._state, 'allowed_mentions', None)
params = handle_message_parameters( params = handle_message_parameters(
content=content, content=content,
file=file, attachments=attachments,
files=files,
embed=embed, embed=embed,
embeds=embeds, embeds=embeds,
allowed_mentions=allowed_mentions, allowed_mentions=allowed_mentions,

Loading…
Cancel
Save