Browse Source

Remove in-place edits and return fresh instances instead

Fixes #4098
pull/7476/head
Rapptz 4 years ago
parent
commit
490bbffc93
  1. 9
      discord/abc.py
  2. 92
      discord/channel.py
  3. 13
      discord/emoji.py
  4. 14
      discord/guild.py
  5. 11
      discord/integrations.py
  6. 25
      discord/interactions.py
  7. 14
      discord/member.py
  8. 13
      discord/message.py
  9. 14
      discord/role.py
  10. 12
      discord/sticker.py
  11. 24
      discord/template.py
  12. 11
      discord/threads.py
  13. 12
      discord/user.py
  14. 38
      discord/webhook/async_.py
  15. 31
      discord/webhook/sync.py

9
discord/abc.py

@ -84,6 +84,7 @@ if TYPE_CHECKING:
from .ui.view import View from .ui.view import View
from .types.channel import ( from .types.channel import (
PermissionOverwrite as PermissionOverwritePayload, PermissionOverwrite as PermissionOverwritePayload,
Channel as ChannelPayload,
GuildChannel as GuildChannelPayload, GuildChannel as GuildChannelPayload,
OverwriteType, OverwriteType,
) )
@ -302,11 +303,8 @@ class GuildChannel:
payload.append(d) payload.append(d)
await http.bulk_channel_update(self.guild.id, payload, reason=reason) await http.bulk_channel_update(self.guild.id, payload, reason=reason)
self.position = position
if parent_id is not _undefined:
self.category_id = int(parent_id) if parent_id else None
async def _edit(self, options: Dict[str, Any], reason: Optional[str]): async def _edit(self, options: Dict[str, Any], reason: Optional[str]) -> Optional[ChannelPayload]:
try: try:
parent = options.pop('category') parent = options.pop('category')
except KeyError: except KeyError:
@ -385,8 +383,7 @@ class GuildChannel:
options['type'] = ch_type.value options['type'] = ch_type.value
if options: if options:
data = await self._state.http.edit_channel(self.id, reason=reason, **options) return await self._state.http.edit_channel(self.id, reason=reason, **options)
self._update(self.guild, data)
def _fill_overwrites(self, data: GuildChannelPayload) -> None: def _fill_overwrites(self, data: GuildChannelPayload) -> None:
self._overwrites = [] self._overwrites = []

92
discord/channel.py

@ -276,11 +276,11 @@ class TextChannel(discord.abc.Messageable, discord.abc.GuildChannel, Hashable):
default_auto_archive_duration: ThreadArchiveDuration = ..., default_auto_archive_duration: ThreadArchiveDuration = ...,
type: ChannelType = ..., type: ChannelType = ...,
overwrites: Mapping[Union[Role, Member, Snowflake], PermissionOverwrite] = ..., overwrites: Mapping[Union[Role, Member, Snowflake], PermissionOverwrite] = ...,
) -> None: ) -> Optional[TextChannel]:
... ...
@overload @overload
async def edit(self) -> None: async def edit(self) -> Optional[TextChannel]:
... ...
async def edit(self, *, reason=None, **options): async def edit(self, *, reason=None, **options):
@ -297,6 +297,9 @@ class TextChannel(discord.abc.Messageable, discord.abc.GuildChannel, Hashable):
.. versionchanged:: 1.4 .. versionchanged:: 1.4
The ``type`` keyword-only parameter was added. The ``type`` keyword-only parameter was added.
.. versionchanged:: 2.0
Edits are no longer in-place, the newly edited channel is returned instead.
Parameters Parameters
---------- ----------
name: :class:`str` name: :class:`str`
@ -338,8 +341,18 @@ class TextChannel(discord.abc.Messageable, discord.abc.GuildChannel, Hashable):
You do not have permissions to edit the channel. You do not have permissions to edit the channel.
HTTPException HTTPException
Editing the channel failed. Editing the channel failed.
Returns
--------
Optional[:class:`.TextChannel`]
The newly edited text channel. If the edit was only positional
then ``None`` is returned instead.
""" """
await self._edit(options, reason=reason)
payload = await self._edit(options, reason=reason)
if payload is not None:
# the payload will always be the proper channel payload
return self.__class__(state=self._state, guild=self.guild, data=payload) # type: ignore
@utils.copy_doc(discord.abc.GuildChannel.clone) @utils.copy_doc(discord.abc.GuildChannel.clone)
async def clone(self, *, name: Optional[str] = None, reason: Optional[str] = None) -> TextChannel: async def clone(self, *, name: Optional[str] = None, reason: Optional[str] = None) -> TextChannel:
@ -958,11 +971,11 @@ class VoiceChannel(VocalGuildChannel):
rtc_region: Optional[VoiceRegion] = ..., rtc_region: Optional[VoiceRegion] = ...,
video_quality_mode: VideoQualityMode = ..., video_quality_mode: VideoQualityMode = ...,
reason: Optional[str] = ..., reason: Optional[str] = ...,
) -> None: ) -> Optional[VoiceChannel]:
... ...
@overload @overload
async def edit(self) -> None: async def edit(self) -> Optional[VoiceChannel]:
... ...
async def edit(self, *, reason=None, **options): async def edit(self, *, reason=None, **options):
@ -976,6 +989,9 @@ class VoiceChannel(VocalGuildChannel):
.. versionchanged:: 1.3 .. versionchanged:: 1.3
The ``overwrites`` keyword-only parameter was added. The ``overwrites`` keyword-only parameter was added.
.. versionchanged:: 2.0
Edits are no longer in-place, the newly edited channel is returned instead.
Parameters Parameters
---------- ----------
name: :class:`str` name: :class:`str`
@ -1015,9 +1031,18 @@ class VoiceChannel(VocalGuildChannel):
You do not have permissions to edit the channel. You do not have permissions to edit the channel.
HTTPException HTTPException
Editing the channel failed. Editing the channel failed.
Returns
--------
Optional[:class:`.VoiceChannel`]
The newly edited voice channel. If the edit was only positional
then ``None`` is returned instead.
""" """
await self._edit(options, reason=reason) payload = await self._edit(options, reason=reason)
if payload is not None:
# the payload will always be the proper channel payload
return self.__class__(state=self._state, guild=self.guild, data=payload) # type: ignore
class StageChannel(VocalGuildChannel): class StageChannel(VocalGuildChannel):
@ -1225,11 +1250,11 @@ class StageChannel(VocalGuildChannel):
rtc_region: Optional[VoiceRegion] = ..., rtc_region: Optional[VoiceRegion] = ...,
video_quality_mode: VideoQualityMode = ..., video_quality_mode: VideoQualityMode = ...,
reason: Optional[str] = ..., reason: Optional[str] = ...,
) -> None: ) -> Optional[StageChannel]:
... ...
@overload @overload
async def edit(self) -> None: async def edit(self) -> Optional[StageChannel]:
... ...
async def edit(self, *, reason=None, **options): async def edit(self, *, reason=None, **options):
@ -1243,6 +1268,9 @@ class StageChannel(VocalGuildChannel):
.. versionchanged:: 2.0 .. versionchanged:: 2.0
The ``topic`` parameter must now be set via :attr:`create_instance`. The ``topic`` parameter must now be set via :attr:`create_instance`.
.. versionchanged:: 2.0
Edits are no longer in-place, the newly edited channel is returned instead.
Parameters Parameters
---------- ----------
name: :class:`str` name: :class:`str`
@ -1276,9 +1304,18 @@ class StageChannel(VocalGuildChannel):
You do not have permissions to edit the channel. You do not have permissions to edit the channel.
HTTPException HTTPException
Editing the channel failed. Editing the channel failed.
Returns
--------
Optional[:class:`.StageChannel`]
The newly edited stage channel. If the edit was only positional
then ``None`` is returned instead.
""" """
await self._edit(options, reason=reason) payload = await self._edit(options, reason=reason)
if payload is not None:
# the payload will always be the proper channel payload
return self.__class__(state=self._state, guild=self.guild, data=payload) # type: ignore
class CategoryChannel(discord.abc.GuildChannel, Hashable): class CategoryChannel(discord.abc.GuildChannel, Hashable):
@ -1367,11 +1404,11 @@ class CategoryChannel(discord.abc.GuildChannel, Hashable):
nsfw: bool = ..., nsfw: bool = ...,
overwrites: Mapping[Union[Role, Member], PermissionOverwrite] = ..., overwrites: Mapping[Union[Role, Member], PermissionOverwrite] = ...,
reason: Optional[str] = ..., reason: Optional[str] = ...,
) -> None: ) -> Optional[CategoryChannel]:
... ...
@overload @overload
async def edit(self) -> None: async def edit(self) -> Optional[CategoryChannel]:
... ...
async def edit(self, *, reason=None, **options): async def edit(self, *, reason=None, **options):
@ -1385,6 +1422,9 @@ class CategoryChannel(discord.abc.GuildChannel, Hashable):
.. versionchanged:: 1.3 .. versionchanged:: 1.3
The ``overwrites`` keyword-only parameter was added. The ``overwrites`` keyword-only parameter was added.
.. versionchanged:: 2.0
Edits are no longer in-place, the newly edited channel is returned instead.
Parameters Parameters
---------- ----------
name: :class:`str` name: :class:`str`
@ -1407,9 +1447,18 @@ class CategoryChannel(discord.abc.GuildChannel, Hashable):
You do not have permissions to edit the category. You do not have permissions to edit the category.
HTTPException HTTPException
Editing the category failed. Editing the category failed.
Returns
--------
Optional[:class:`.CategoryChannel`]
The newly edited category channel. If the edit was only positional
then ``None`` is returned instead.
""" """
await self._edit(options=options, reason=reason) payload = await self._edit(options, reason=reason)
if payload is not None:
# the payload will always be the proper channel payload
return self.__class__(state=self._state, guild=self.guild, data=payload) # type: ignore
@utils.copy_doc(discord.abc.GuildChannel.move) @utils.copy_doc(discord.abc.GuildChannel.move)
async def move(self, **kwargs): async def move(self, **kwargs):
@ -1599,11 +1648,11 @@ class StoreChannel(discord.abc.GuildChannel, Hashable):
category: Optional[CategoryChannel], category: Optional[CategoryChannel],
reason: Optional[str], reason: Optional[str],
overwrites: Mapping[Union[Role, Member], PermissionOverwrite], overwrites: Mapping[Union[Role, Member], PermissionOverwrite],
) -> None: ) -> Optional[StoreChannel]:
... ...
@overload @overload
async def edit(self) -> None: async def edit(self) -> Optional[StoreChannel]:
... ...
async def edit(self, *, reason=None, **options): async def edit(self, *, reason=None, **options):
@ -1614,6 +1663,9 @@ class StoreChannel(discord.abc.GuildChannel, Hashable):
You must have the :attr:`~Permissions.manage_channels` permission to You must have the :attr:`~Permissions.manage_channels` permission to
use this. use this.
.. versionchanged:: 2.0
Edits are no longer in-place, the newly edited channel is returned instead.
Parameters Parameters
---------- ----------
name: :class:`str` name: :class:`str`
@ -1645,8 +1697,18 @@ class StoreChannel(discord.abc.GuildChannel, Hashable):
You do not have permissions to edit the channel. You do not have permissions to edit the channel.
HTTPException HTTPException
Editing the channel failed. Editing the channel failed.
Returns
--------
Optional[:class:`.StoreChannel`]
The newly edited store channel. If the edit was only positional
then ``None`` is returned instead.
""" """
await self._edit(options, reason=reason)
payload = await self._edit(options, reason=reason)
if payload is not None:
# the payload will always be the proper channel payload
return self.__class__(state=self._state, guild=self.guild, data=payload) # type: ignore
DMC = TypeVar('DMC', bound='DMChannel') DMC = TypeVar('DMC', bound='DMChannel')

13
discord/emoji.py

@ -212,7 +212,7 @@ class Emoji(_EmojiTag, AssetMixin):
await self._state.http.delete_custom_emoji(self.guild.id, self.id, reason=reason) await self._state.http.delete_custom_emoji(self.guild.id, self.id, reason=reason)
async def edit(self, *, name: str = MISSING, roles: List[Snowflake] = MISSING, reason: Optional[str] = None) -> None: async def edit(self, *, name: str = MISSING, roles: List[Snowflake] = MISSING, reason: Optional[str] = None) -> Emoji:
r"""|coro| r"""|coro|
Edits the custom emoji. Edits the custom emoji.
@ -220,6 +220,9 @@ class Emoji(_EmojiTag, AssetMixin):
You must have :attr:`~Permissions.manage_emojis` permission to You must have :attr:`~Permissions.manage_emojis` permission to
do this. do this.
.. versionchanged:: 2.0
The newly updated emoji is returned.
Parameters Parameters
----------- -----------
name: :class:`str` name: :class:`str`
@ -235,6 +238,11 @@ class Emoji(_EmojiTag, AssetMixin):
You are not allowed to edit emojis. You are not allowed to edit emojis.
HTTPException HTTPException
An error occurred editing the emoji. An error occurred editing the emoji.
Returns
--------
:class:`Emoji`
The newly updated emoji.
""" """
payload = {} payload = {}
@ -243,4 +251,5 @@ class Emoji(_EmojiTag, AssetMixin):
if roles is not MISSING: if roles is not MISSING:
payload['roles'] = [role.id for role in roles] payload['roles'] = [role.id for role in roles]
await self._state.http.edit_custom_emoji(self.guild.id, self.id, payload=payload, reason=reason) data = await self._state.http.edit_custom_emoji(self.guild.id, self.id, payload=payload, reason=reason)
return Emoji(guild=self.guild, data=data, state=self._state)

14
discord/guild.py

@ -1356,7 +1356,7 @@ class Guild(Hashable):
preferred_locale: str = MISSING, preferred_locale: str = MISSING,
rules_channel: Optional[TextChannel] = MISSING, rules_channel: Optional[TextChannel] = MISSING,
public_updates_channel: Optional[TextChannel] = MISSING, public_updates_channel: Optional[TextChannel] = MISSING,
) -> None: ) -> Guild:
r"""|coro| r"""|coro|
Edits the guild. Edits the guild.
@ -1370,6 +1370,9 @@ class Guild(Hashable):
.. versionchanged:: 2.0 .. versionchanged:: 2.0
The `discovery_splash` and `community` keyword-only parameters were added. The `discovery_splash` and `community` keyword-only parameters were added.
.. versionchanged:: 2.0
The newly updated guild is returned.
Parameters Parameters
---------- ----------
name: :class:`str` name: :class:`str`
@ -1443,6 +1446,12 @@ class Guild(Hashable):
The image format passed in to ``icon`` is invalid. It must be The image format passed in to ``icon`` is invalid. It must be
PNG or JPG. This is also raised if you are not the owner of the PNG or JPG. This is also raised if you are not the owner of the
guild and request an ownership transfer. guild and request an ownership transfer.
Returns
--------
:class:`Guild`
The newly updated guild. Note that this has the same limitations as
mentioned in :meth:`Client.fetch_guild` and may not have full data.
""" """
http = self._state.http http = self._state.http
@ -1555,7 +1564,8 @@ class Guild(Hashable):
fields['features'] = features fields['features'] = features
await http.edit_guild(self.id, reason=reason, **fields) data = await http.edit_guild(self.id, reason=reason, **fields)
return Guild(data=data, state=self._state)
async def fetch_channels(self) -> Sequence[GuildChannel]: async def fetch_channels(self) -> Sequence[GuildChannel]:
"""|coro| """|coro|

11
discord/integrations.py

@ -262,17 +262,10 @@ class StreamIntegration(Integration):
if enable_emoticons is not MISSING: if enable_emoticons is not MISSING:
payload['enable_emoticons'] = enable_emoticons payload['enable_emoticons'] = enable_emoticons
# This endpoint is undocumented.
# Unsure if it returns the data or not as a result
await self._state.http.edit_integration(self.guild.id, self.id, **payload) await self._state.http.edit_integration(self.guild.id, self.id, **payload)
if expire_behaviour is not MISSING:
self.expire_behaviour = expire_behaviour
if enable_emoticons is not MISSING:
self.enable_emoticons = enable_emoticons
if expire_grace_period is not MISSING:
self.expire_grace_period = expire_grace_period
async def sync(self) -> None: async def sync(self) -> None:
"""|coro| """|coro|

25
discord/interactions.py

@ -261,7 +261,7 @@ class Interaction:
files: List[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:
"""|coro| """|coro|
Edits the original interaction response message. Edits the original interaction response message.
@ -302,7 +302,12 @@ class Interaction:
TypeError TypeError
You specified both ``embed`` and ``embeds`` or ``file`` and ``files`` You specified both ``embed`` and ``embeds`` or ``file`` and ``files``
ValueError ValueError
The length of ``embeds`` was invalid The length of ``embeds`` was invalid.
Returns
--------
:class:`InteractionMessage`
The newly edited message.
""" """
previous_mentions: Optional[AllowedMentions] = self._state.allowed_mentions previous_mentions: Optional[AllowedMentions] = self._state.allowed_mentions
@ -326,8 +331,11 @@ class Interaction:
files=params.files, files=params.files,
) )
# The message channel types should always match
message = InteractionMessage(state=self._state, channel=self.channel, data=data) # type: ignore
if view and not view.is_finished(): if view and not view.is_finished():
self._state.store_view(view, int(data['id'])) self._state.store_view(view, message.id)
return message
async def delete_original_message(self) -> None: async def delete_original_message(self) -> None:
"""|coro| """|coro|
@ -672,7 +680,7 @@ class InteractionMessage(Message):
files: List[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:
"""|coro| """|coro|
Edits the message. Edits the message.
@ -707,9 +715,14 @@ class InteractionMessage(Message):
TypeError TypeError
You specified both ``embed`` and ``embeds`` or ``file`` and ``files`` You specified both ``embed`` and ``embeds`` or ``file`` and ``files``
ValueError ValueError
The length of ``embeds`` was invalid The length of ``embeds`` was invalid.
Returns
---------
:class:`InteractionMessage`
The newly edited message.
""" """
await self._state._interaction.edit_original_message( return await self._state._interaction.edit_original_message(
content=content, content=content,
embeds=embeds, embeds=embeds,
embed=embed, embed=embed,

14
discord/member.py

@ -644,7 +644,7 @@ class Member(discord.abc.Messageable, _UserTag):
roles: List[discord.abc.Snowflake] = MISSING, roles: List[discord.abc.Snowflake] = MISSING,
voice_channel: Optional[VocalGuildChannel] = MISSING, voice_channel: Optional[VocalGuildChannel] = MISSING,
reason: Optional[str] = None, reason: Optional[str] = None,
) -> None: ) -> Optional[Member]:
"""|coro| """|coro|
Edits the member's data. Edits the member's data.
@ -670,6 +670,9 @@ class Member(discord.abc.Messageable, _UserTag):
.. versionchanged:: 1.1 .. versionchanged:: 1.1
Can now pass ``None`` to ``voice_channel`` to kick a member from voice. Can now pass ``None`` to ``voice_channel`` to kick a member from voice.
.. versionchanged:: 2.0
The newly member is now optionally returned, if applicable.
Parameters Parameters
----------- -----------
nick: Optional[:class:`str`] nick: Optional[:class:`str`]
@ -697,6 +700,12 @@ class Member(discord.abc.Messageable, _UserTag):
You do not have the proper permissions to the action requested. You do not have the proper permissions to the action requested.
HTTPException HTTPException
The operation failed. The operation failed.
Returns
--------
Optional[:class:`.Member`]
The newly updated member, if applicable. This is only returned
when certain fields are updated.
""" """
http = self._state.http http = self._state.http
guild_id = self.guild.id guild_id = self.guild.id
@ -739,7 +748,8 @@ class Member(discord.abc.Messageable, _UserTag):
payload['roles'] = tuple(r.id for r in roles) payload['roles'] = tuple(r.id for r in roles)
if payload: if payload:
await http.edit_member(guild_id, self.id, reason=reason, **payload) data = await http.edit_member(guild_id, self.id, reason=reason, **payload)
return Member(data=data, guild=self.guild, state=self._state)
async def request_to_speak(self) -> None: async def request_to_speak(self) -> None:
"""|coro| """|coro|

13
discord/message.py

@ -1157,7 +1157,7 @@ class Message(Hashable):
delete_after: Optional[float] = ..., delete_after: Optional[float] = ...,
allowed_mentions: Optional[AllowedMentions] = ..., allowed_mentions: Optional[AllowedMentions] = ...,
view: Optional[View] = ..., view: Optional[View] = ...,
) -> None: ) -> Message:
... ...
@overload @overload
@ -1171,7 +1171,7 @@ class Message(Hashable):
delete_after: Optional[float] = ..., delete_after: Optional[float] = ...,
allowed_mentions: Optional[AllowedMentions] = ..., allowed_mentions: Optional[AllowedMentions] = ...,
view: Optional[View] = ..., view: Optional[View] = ...,
) -> None: ) -> Message:
... ...
async def edit( async def edit(
@ -1184,7 +1184,7 @@ class Message(Hashable):
delete_after: Optional[float] = None, delete_after: Optional[float] = None,
allowed_mentions: Optional[AllowedMentions] = MISSING, allowed_mentions: Optional[AllowedMentions] = MISSING,
view: Optional[View] = MISSING, view: Optional[View] = MISSING,
) -> None: ) -> Message:
"""|coro| """|coro|
Edits the message. Edits the message.
@ -1286,9 +1286,8 @@ class Message(Hashable):
else: else:
payload['components'] = [] payload['components'] = []
if payload: data = await self._state.http.edit_message(self.channel.id, self.id, **payload)
data = await self._state.http.edit_message(self.channel.id, self.id, **payload) message = Message(state=self._state, channel=self.channel, data=data)
self._update(data)
if view and not view.is_finished(): if view and not view.is_finished():
self._state.store_view(view, self.id) self._state.store_view(view, self.id)
@ -1296,6 +1295,8 @@ class Message(Hashable):
if delete_after is not None: if delete_after is not None:
await self.delete(delay=delete_after) await self.delete(delay=delete_after)
return message
async def publish(self) -> None: async def publish(self) -> None:
"""|coro| """|coro|

14
discord/role.py

@ -351,7 +351,7 @@ class Role(Hashable):
mentionable: bool = MISSING, mentionable: bool = MISSING,
position: int = MISSING, position: int = MISSING,
reason: Optional[str] = MISSING, reason: Optional[str] = MISSING,
) -> None: ) -> Optional[Role]:
"""|coro| """|coro|
Edits the role. Edits the role.
@ -364,6 +364,9 @@ class Role(Hashable):
.. versionchanged:: 1.4 .. versionchanged:: 1.4
Can now pass ``int`` to ``colour`` keyword-only parameter. Can now pass ``int`` to ``colour`` keyword-only parameter.
.. versionchanged:: 2.0
Edits are no longer in-place, the newly edited role is returned instead.
Parameters Parameters
----------- -----------
name: :class:`str` name: :class:`str`
@ -391,11 +394,14 @@ class Role(Hashable):
InvalidArgument InvalidArgument
An invalid position was given or the default An invalid position was given or the default
role was asked to be moved. role was asked to be moved.
"""
Returns
--------
:class:`Role`
The newly edited role.
"""
if position is not MISSING: if position is not MISSING:
await self._move(position, reason=reason) await self._move(position, reason=reason)
self.position = position
payload: Dict[str, Any] = {} payload: Dict[str, Any] = {}
if color is not MISSING: if color is not MISSING:
@ -420,7 +426,7 @@ class Role(Hashable):
payload['mentionable'] = mentionable payload['mentionable'] = mentionable
data = await self._state.http.edit_role(self.guild.id, self.id, reason=reason, **payload) data = await self._state.http.edit_role(self.guild.id, self.id, reason=reason, **payload)
self._update(data) return Role(guild=self.guild, data=data, state=self._state)
async def delete(self, *, reason: Optional[str] = None) -> None: async def delete(self, *, reason: Optional[str] = None) -> None:
"""|coro| """|coro|

12
discord/sticker.py

@ -440,10 +440,10 @@ class GuildSticker(Sticker):
description: str = MISSING, description: str = MISSING,
emoji: str = MISSING, emoji: str = MISSING,
reason: Optional[str] = None, reason: Optional[str] = None,
) -> None: ) -> GuildSticker:
"""|coro| """|coro|
Edits a :class:`Sticker` for the guild. Edits a :class:`GuildSticker` for the guild.
Parameters Parameters
----------- -----------
@ -462,6 +462,11 @@ class GuildSticker(Sticker):
You are not allowed to edit stickers. You are not allowed to edit stickers.
HTTPException HTTPException
An error occurred editing the sticker. An error occurred editing the sticker.
Returns
--------
:class:`GuildSticker`
The newly modified sticker.
""" """
payload = {} payload = {}
@ -482,8 +487,7 @@ class GuildSticker(Sticker):
payload['tags'] = emoji payload['tags'] = emoji
data: GuildStickerPayload = await self._state.http.modify_guild_sticker(self.guild_id, self.id, payload, reason) data: GuildStickerPayload = await self._state.http.modify_guild_sticker(self.guild_id, self.id, payload, reason)
return GuildSticker(state=self._state, data=data)
self._from_data(data)
async def delete(self, *, reason: Optional[str] = None) -> None: async def delete(self, *, reason: Optional[str] = None) -> None:
"""|coro| """|coro|

24
discord/template.py

@ -206,7 +206,7 @@ class Template:
data = await self._state.http.create_from_template(self.code, name, region_value, icon) data = await self._state.http.create_from_template(self.code, name, region_value, icon)
return Guild(data=data, state=self._state) return Guild(data=data, state=self._state)
async def sync(self) -> None: async def sync(self) -> Template:
"""|coro| """|coro|
Sync the template to the guild's current state. Sync the template to the guild's current state.
@ -216,6 +216,9 @@ class Template:
.. versionadded:: 1.7 .. versionadded:: 1.7
.. versionchanged:: 2.0
The template is no longer edited in-place, instead it is returned.
Raises Raises
------- -------
HTTPException HTTPException
@ -224,17 +227,22 @@ class Template:
You don't have permissions to edit the template. You don't have permissions to edit the template.
NotFound NotFound
This template does not exist. This template does not exist.
Returns
--------
:class:`Template`
The newly edited template.
""" """
data = await self._state.http.sync_template(self.source_guild.id, self.code) data = await self._state.http.sync_template(self.source_guild.id, self.code)
self._store(data) return Template(state=self._state, data=data)
async def edit( async def edit(
self, self,
*, *,
name: str = MISSING, name: str = MISSING,
description: Optional[str] = MISSING, description: Optional[str] = MISSING,
) -> None: ) -> Template:
"""|coro| """|coro|
Edit the template metadata. Edit the template metadata.
@ -244,6 +252,9 @@ class Template:
.. versionadded:: 1.7 .. versionadded:: 1.7
.. versionchanged:: 2.0
The template is no longer edited in-place, instead it is returned.
Parameters Parameters
------------ ------------
name: :class:`str` name: :class:`str`
@ -259,6 +270,11 @@ class Template:
You don't have permissions to edit the template. You don't have permissions to edit the template.
NotFound NotFound
This template does not exist. This template does not exist.
Returns
--------
:class:`Template`
The newly edited template.
""" """
payload = {} payload = {}
@ -268,7 +284,7 @@ class Template:
payload['description'] = description payload['description'] = description
data = await self._state.http.edit_template(self.source_guild.id, self.code, payload) data = await self._state.http.edit_template(self.source_guild.id, self.code, payload)
self._store(data) return Template(state=self._state, data=data)
async def delete(self) -> None: async def delete(self) -> None:
"""|coro| """|coro|

11
discord/threads.py

@ -523,7 +523,7 @@ class Thread(Messageable, Hashable):
locked: bool = MISSING, locked: bool = MISSING,
slowmode_delay: int = MISSING, slowmode_delay: int = MISSING,
auto_archive_duration: ThreadArchiveDuration = MISSING, auto_archive_duration: ThreadArchiveDuration = MISSING,
): ) -> Thread:
"""|coro| """|coro|
Edits the thread. Edits the thread.
@ -556,6 +556,11 @@ class Thread(Messageable, Hashable):
You do not have permissions to edit the thread. You do not have permissions to edit the thread.
HTTPException HTTPException
Editing the thread failed. Editing the thread failed.
Returns
--------
:class:`Thread`
The newly edited thread.
""" """
payload = {} payload = {}
if name is not MISSING: if name is not MISSING:
@ -569,7 +574,9 @@ class Thread(Messageable, Hashable):
if slowmode_delay is not MISSING: if slowmode_delay is not MISSING:
payload['rate_limit_per_user'] = slowmode_delay payload['rate_limit_per_user'] = slowmode_delay
await self._state.http.edit_channel(self.id, **payload) data = await self._state.http.edit_channel(self.id, **payload)
# The data payload will always be a Thread payload
return Thread(data=data, state=self._state, guild=self.guild) # type: ignore
async def join(self): async def join(self):
"""|coro| """|coro|

12
discord/user.py

@ -349,7 +349,7 @@ class ClientUser(BaseUser):
self._flags = data.get('flags', 0) self._flags = data.get('flags', 0)
self.mfa_enabled = data.get('mfa_enabled', False) self.mfa_enabled = data.get('mfa_enabled', False)
async def edit(self, *, username: str = MISSING, avatar: bytes = MISSING) -> None: async def edit(self, *, username: str = MISSING, avatar: bytes = MISSING) -> ClientUser:
"""|coro| """|coro|
Edits the current profile of the client. Edits the current profile of the client.
@ -363,6 +363,9 @@ class ClientUser(BaseUser):
The only image formats supported for uploading is JPEG and PNG. The only image formats supported for uploading is JPEG and PNG.
.. versionchanged:: 2.0
The edit is no longer in-place, instead the newly edited client user is returned.
Parameters Parameters
----------- -----------
username: :class:`str` username: :class:`str`
@ -377,6 +380,11 @@ class ClientUser(BaseUser):
Editing your profile failed. Editing your profile failed.
InvalidArgument InvalidArgument
Wrong image format passed for ``avatar``. Wrong image format passed for ``avatar``.
Returns
---------
:class:`ClientUser`
The newly edited client user.
""" """
payload: Dict[str, Any] = {} payload: Dict[str, Any] = {}
if username is not MISSING: if username is not MISSING:
@ -386,7 +394,7 @@ class ClientUser(BaseUser):
payload['avatar'] = _bytes_to_base64_data(avatar) payload['avatar'] = _bytes_to_base64_data(avatar)
data: UserPayload = await self._state.http.edit_profile(payload) data: UserPayload = await self._state.http.edit_profile(payload)
self._update(data) return ClientUser(state=self._state, data=data)
class User(BaseUser, discord.abc.Messageable): class User(BaseUser, discord.abc.Messageable):

38
discord/webhook/async_.py

@ -647,13 +647,16 @@ class WebhookMessage(Message):
files: List[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:
"""|coro| """|coro|
Edits the message. Edits the message.
.. versionadded:: 1.6 .. versionadded:: 1.6
.. versionchanged:: 2.0
The edit is no longer in-place, instead the newly edited message is returned.
Parameters Parameters
------------ ------------
content: Optional[:class:`str`] content: Optional[:class:`str`]
@ -693,8 +696,13 @@ class WebhookMessage(Message):
The length of ``embeds`` was invalid The length of ``embeds`` was invalid
InvalidArgument InvalidArgument
There was no token associated with this webhook. There was no token associated with this webhook.
Returns
--------
:class:`WebhookMessage`
The newly edited message.
""" """
await self._state._webhook.edit_message( return await self._state._webhook.edit_message(
self.id, self.id,
content=content, content=content,
embeds=embeds, embeds=embeds,
@ -1117,7 +1125,7 @@ class Webhook(BaseWebhook):
avatar: Optional[bytes] = MISSING, avatar: Optional[bytes] = MISSING,
channel: Optional[Snowflake] = None, channel: Optional[Snowflake] = None,
prefer_auth: bool = True, prefer_auth: bool = True,
): ) -> Webhook:
"""|coro| """|coro|
Edits this Webhook. Edits this Webhook.
@ -1164,6 +1172,7 @@ class Webhook(BaseWebhook):
adapter = async_context.get() adapter = async_context.get()
data: Optional[WebhookPayload] = None
# If a channel is given, always use the authenticated endpoint # If a channel is given, always use the authenticated endpoint
if channel is not None: if channel is not None:
if self.auth_token is None: if self.auth_token is None:
@ -1171,17 +1180,18 @@ class Webhook(BaseWebhook):
payload['channel_id'] = channel.id payload['channel_id'] = channel.id
data = await adapter.edit_webhook(self.id, self.auth_token, payload=payload, session=self.session, reason=reason) data = await adapter.edit_webhook(self.id, self.auth_token, payload=payload, session=self.session, reason=reason)
self._update(data)
return
if prefer_auth and self.auth_token: if prefer_auth and self.auth_token:
data = await adapter.edit_webhook(self.id, self.auth_token, payload=payload, session=self.session, reason=reason) data = await adapter.edit_webhook(self.id, self.auth_token, payload=payload, session=self.session, reason=reason)
self._update(data)
elif self.token: elif self.token:
data = await adapter.edit_webhook_with_token( data = await adapter.edit_webhook_with_token(
self.id, self.token, payload=payload, session=self.session, reason=reason self.id, self.token, payload=payload, session=self.session, reason=reason
) )
self._update(data)
if data is None:
raise RuntimeError('Unreachable code hit: data was not assigned')
return Webhook(data=data, session=self.session, token=self.auth_token, state=self._state)
def _create_message(self, data): def _create_message(self, data):
state = _WebhookState(self, parent=self._state) state = _WebhookState(self, parent=self._state)
@ -1446,7 +1456,7 @@ class Webhook(BaseWebhook):
files: List[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:
"""|coro| """|coro|
Edits a message owned by this webhook. Edits a message owned by this webhook.
@ -1456,6 +1466,9 @@ class Webhook(BaseWebhook):
.. versionadded:: 1.6 .. versionadded:: 1.6
.. versionchanged:: 2.0
The edit is no longer in-place, instead the newly edited message is returned.
Parameters Parameters
------------ ------------
message_id: :class:`int` message_id: :class:`int`
@ -1499,6 +1512,11 @@ class Webhook(BaseWebhook):
InvalidArgument InvalidArgument
There was no token associated with this webhook or the webhook had There was no token associated with this webhook or the webhook had
no state. no state.
Returns
--------
:class:`WebhookMessage`
The newly edited webhook message.
""" """
if self.token is None: if self.token is None:
@ -1522,7 +1540,7 @@ class Webhook(BaseWebhook):
previous_allowed_mentions=previous_mentions, previous_allowed_mentions=previous_mentions,
) )
adapter = async_context.get() adapter = async_context.get()
await adapter.edit_webhook_message( data = await adapter.edit_webhook_message(
self.id, self.id,
self.token, self.token,
message_id, message_id,
@ -1532,8 +1550,10 @@ class Webhook(BaseWebhook):
files=params.files, files=params.files,
) )
message = self._create_message(data)
if view and not view.is_finished(): if view and not view.is_finished():
self._state.store_view(view, message_id) self._state.store_view(view, message_id)
return message
async def delete_message(self, message_id: int): async def delete_message(self, message_id: int):
"""|coro| """|coro|

31
discord/webhook/sync.py

@ -383,7 +383,7 @@ class SyncWebhookMessage(Message):
file: File = MISSING, file: File = MISSING,
files: List[File] = MISSING, files: List[File] = MISSING,
allowed_mentions: Optional[AllowedMentions] = None, allowed_mentions: Optional[AllowedMentions] = None,
): ) -> SyncWebhookMessage:
"""Edits the message. """Edits the message.
Parameters Parameters
@ -416,8 +416,13 @@ class SyncWebhookMessage(Message):
The length of ``embeds`` was invalid The length of ``embeds`` was invalid
InvalidArgument InvalidArgument
There was no token associated with this webhook. There was no token associated with this webhook.
Returns
--------
:class:`SyncWebhookMessage`
The newly edited message.
""" """
self._state._webhook.edit_message( return self._state._webhook.edit_message(
self.id, self.id,
content=content, content=content,
embeds=embeds, embeds=embeds,
@ -687,7 +692,7 @@ class SyncWebhook(BaseWebhook):
avatar: Optional[bytes] = MISSING, avatar: Optional[bytes] = MISSING,
channel: Optional[Snowflake] = None, channel: Optional[Snowflake] = None,
prefer_auth: bool = True, prefer_auth: bool = True,
): ) -> SyncWebhook:
"""Edits this Webhook. """Edits this Webhook.
Parameters Parameters
@ -715,6 +720,11 @@ class SyncWebhook(BaseWebhook):
InvalidArgument InvalidArgument
This webhook does not have a token associated with it This webhook does not have a token associated with it
or it tried editing a channel without authentication. or it tried editing a channel without authentication.
Returns
--------
:class:`SyncWebhook`
The newly edited webhook.
""" """
if self.token is None and self.auth_token is None: if self.token is None and self.auth_token is None:
raise InvalidArgument('This webhook does not have a token associated with it') raise InvalidArgument('This webhook does not have a token associated with it')
@ -728,6 +738,7 @@ class SyncWebhook(BaseWebhook):
adapter: WebhookAdapter = _get_webhook_adapter() adapter: WebhookAdapter = _get_webhook_adapter()
data: Optional[WebhookPayload] = None
# If a channel is given, always use the authenticated endpoint # If a channel is given, always use the authenticated endpoint
if channel is not None: if channel is not None:
if self.auth_token is None: if self.auth_token is None:
@ -735,15 +746,16 @@ class SyncWebhook(BaseWebhook):
payload['channel_id'] = channel.id payload['channel_id'] = channel.id
data = adapter.edit_webhook(self.id, self.auth_token, payload=payload, session=self.session, reason=reason) data = adapter.edit_webhook(self.id, self.auth_token, payload=payload, session=self.session, reason=reason)
self._update(data)
return
if prefer_auth and self.auth_token: if prefer_auth and self.auth_token:
data = adapter.edit_webhook(self.id, self.auth_token, payload=payload, session=self.session, reason=reason) data = adapter.edit_webhook(self.id, self.auth_token, payload=payload, session=self.session, reason=reason)
self._update(data)
elif self.token: elif self.token:
data = adapter.edit_webhook_with_token(self.id, self.token, payload=payload, session=self.session, reason=reason) data = adapter.edit_webhook_with_token(self.id, self.token, payload=payload, session=self.session, reason=reason)
self._update(data)
if data is None:
raise RuntimeError('Unreachable code hit: data was not assigned')
return SyncWebhook(data=data, session=self.session, token=self.auth_token, state=self._state)
def _create_message(self, data): def _create_message(self, data):
state = _WebhookState(self, parent=self._state) state = _WebhookState(self, parent=self._state)
@ -955,7 +967,7 @@ class SyncWebhook(BaseWebhook):
file: File = MISSING, file: File = MISSING,
files: List[File] = MISSING, files: List[File] = MISSING,
allowed_mentions: Optional[AllowedMentions] = None, allowed_mentions: Optional[AllowedMentions] = None,
): ) -> SyncWebhookMessage:
"""Edits a message owned by this webhook. """Edits a message owned by this webhook.
This is a lower level interface to :meth:`WebhookMessage.edit` in case This is a lower level interface to :meth:`WebhookMessage.edit` in case
@ -1011,7 +1023,7 @@ class SyncWebhook(BaseWebhook):
previous_allowed_mentions=previous_mentions, previous_allowed_mentions=previous_mentions,
) )
adapter: WebhookAdapter = _get_webhook_adapter() adapter: WebhookAdapter = _get_webhook_adapter()
adapter.edit_webhook_message( data = adapter.edit_webhook_message(
self.id, self.id,
self.token, self.token,
message_id, message_id,
@ -1020,6 +1032,7 @@ class SyncWebhook(BaseWebhook):
multipart=params.multipart, multipart=params.multipart,
files=params.files, files=params.files,
) )
return self._create_message(data)
def delete_message(self, message_id: int): def delete_message(self, message_id: int):
"""Deletes a message owned by this webhook. """Deletes a message owned by this webhook.

Loading…
Cancel
Save