Browse Source

Add support for audit log reasons.

Most routes now have a 'reason' keyword argument.
pull/572/head
Rapptz 8 years ago
parent
commit
dff6bcc745
  1. 35
      discord/abc.py
  2. 40
      discord/channel.py
  3. 15
      discord/emoji.py
  4. 62
      discord/guild.py
  5. 127
      discord/http.py
  6. 9
      discord/invite.py
  7. 30
      discord/member.py
  8. 9
      discord/message.py
  9. 21
      discord/role.py

35
discord/abc.py

@ -121,7 +121,7 @@ class GuildChannel:
return self.name return self.name
@asyncio.coroutine @asyncio.coroutine
def _move(self, position): def _move(self, position, *, reason):
if position < 0: if position < 0:
raise InvalidArgument('Channel position cannot be less than 0.') raise InvalidArgument('Channel position cannot be less than 0.')
@ -145,7 +145,7 @@ class GuildChannel:
channels.insert(position, self) channels.insert(position, self)
payload = [{'id': c.id, 'position': index } for index, c in enumerate(channels)] payload = [{'id': c.id, 'position': index } for index, c in enumerate(channels)]
yield from http.move_channel_position(self.guild.id, payload) yield from http.move_channel_position(self.guild.id, payload, reason=reason)
def _fill_overwrites(self, data): def _fill_overwrites(self, data):
self._overwrites = [] self._overwrites = []
@ -351,13 +351,19 @@ class GuildChannel:
return base return base
@asyncio.coroutine @asyncio.coroutine
def delete(self): def delete(self, *, reason=None):
"""|coro| """|coro|
Deletes the channel. Deletes the channel.
You must have Manage Channel permission to use this. You must have Manage Channel permission to use this.
Parameters
-----------
reason: Optional[str]
The reason for deleting this channel.
Shows up on the audit log.
Raises Raises
------- -------
Forbidden Forbidden
@ -367,10 +373,10 @@ class GuildChannel:
HTTPException HTTPException
Deleting the channel failed. Deleting the channel failed.
""" """
yield from self._state.http.delete_channel(self.id) yield from self._state.http.delete_channel(self.id, reason=reason)
@asyncio.coroutine @asyncio.coroutine
def set_permissions(self, target, *, overwrite=_undefined, **permissions): def set_permissions(self, target, *, overwrite=_undefined, reason=None, **permissions):
"""|coro| """|coro|
Sets the channel specific permission overwrites for a target in the Sets the channel specific permission overwrites for a target in the
@ -418,6 +424,8 @@ class GuildChannel:
\*\*permissions \*\*permissions
A keyword argument list of permissions to set for ease of use. A keyword argument list of permissions to set for ease of use.
Cannot be mixed with ``overwrite``. Cannot be mixed with ``overwrite``.
reason: Optional[str]
The reason for doing this action. Shows up on the audit log.
Raises Raises
------- -------
@ -453,15 +461,15 @@ class GuildChannel:
# TODO: wait for event # TODO: wait for event
if overwrite is None: if overwrite is None:
yield from http.delete_channel_permissions(self.id, target.id) yield from http.delete_channel_permissions(self.id, target.id, reason=reason)
elif isinstance(overwrite, PermissionOverwrite): elif isinstance(overwrite, PermissionOverwrite):
(allow, deny) = overwrite.pair() (allow, deny) = overwrite.pair()
yield from http.edit_channel_permissions(self.id, target.id, allow.value, deny.value, perm_type) yield from http.edit_channel_permissions(self.id, target.id, allow.value, deny.value, perm_type, reason=reason)
else: else:
raise InvalidArgument('Invalid overwrite type provided.') raise InvalidArgument('Invalid overwrite type provided.')
@asyncio.coroutine @asyncio.coroutine
def create_invite(self, **fields): def create_invite(self, *, reason=None, **fields):
"""|coro| """|coro|
Creates an instant invite. Creates an instant invite.
@ -481,6 +489,8 @@ class GuildChannel:
Indicates if a unique invite URL should be created. Defaults to True. Indicates if a unique invite URL should be created. Defaults to True.
If this is set to False then it will return a previously created If this is set to False then it will return a previously created
invite. invite.
reason: Optional[str]
The reason for creating this invite. Shows up on the audit log.
Raises Raises
------- -------
@ -493,7 +503,7 @@ class GuildChannel:
The invite that was created. The invite that was created.
""" """
data = yield from self._state.http.create_invite(self.id, **fields) data = yield from self._state.http.create_invite(self.id, reason=reason, **fields)
return Invite.from_incomplete(data=data, state=self._state) return Invite.from_incomplete(data=data, state=self._state)
@asyncio.coroutine @asyncio.coroutine
@ -537,7 +547,7 @@ class Messageable(metaclass=abc.ABCMeta):
raise NotImplementedError raise NotImplementedError
@asyncio.coroutine @asyncio.coroutine
def send(self, content=None, *, tts=False, embed=None, file=None, files=None, delete_after=None): def send(self, content=None, *, tts=False, embed=None, file=None, files=None, reason=None, delete_after=None):
"""|coro| """|coro|
Sends a message to the destination with the content given. Sends a message to the destination with the content given.
@ -571,6 +581,9 @@ class Messageable(metaclass=abc.ABCMeta):
If provided, the number of seconds to wait in the background If provided, the number of seconds to wait in the background
before deleting the message we just sent. If the deletion fails, before deleting the message we just sent. If the deletion fails,
then it is silently ignored. then it is silently ignored.
reason: Optional[str]
The reason for deleting the message, if necessary.
Shows up on the audit log.
Raises Raises
-------- --------
@ -626,7 +639,7 @@ class Messageable(metaclass=abc.ABCMeta):
def delete(): def delete():
yield from asyncio.sleep(delete_after, loop=state.loop) yield from asyncio.sleep(delete_after, loop=state.loop)
try: try:
yield from ret.delete() yield from ret.delete(reason=reason)
except: except:
pass pass
compat.create_task(delete(), loop=state.loop) compat.create_task(delete(), loop=state.loop)

40
discord/channel.py

@ -37,9 +37,9 @@ import asyncio
__all__ = ('TextChannel', 'VoiceChannel', 'DMChannel', 'GroupChannel', '_channel_factory') __all__ = ('TextChannel', 'VoiceChannel', 'DMChannel', 'GroupChannel', '_channel_factory')
@asyncio.coroutine @asyncio.coroutine
def _single_delete_strategy(messages): def _single_delete_strategy(messages, *, reason):
for m in messages: for m in messages:
yield from m.delete() yield from m.delete(reason=reason)
class TextChannel(discord.abc.Messageable, discord.abc.GuildChannel, Hashable): class TextChannel(discord.abc.Messageable, discord.abc.GuildChannel, Hashable):
"""Represents a Discord guild text channel. """Represents a Discord guild text channel.
@ -116,7 +116,7 @@ class TextChannel(discord.abc.Messageable, discord.abc.GuildChannel, Hashable):
return n == 'nsfw' or n[:5] == 'nsfw-' return n == 'nsfw' or n[:5] == 'nsfw-'
@asyncio.coroutine @asyncio.coroutine
def edit(self, **options): def edit(self, *, reason=None, **options):
"""|coro| """|coro|
Edits the channel. Edits the channel.
@ -132,6 +132,8 @@ class TextChannel(discord.abc.Messageable, discord.abc.GuildChannel, Hashable):
The new channel's topic. The new channel's topic.
position: int position: int
The new channel's position. The new channel's position.
reason: Optional[str]
The reason for editing this channel. Shows up on the audit log.
Raises Raises
------ ------
@ -147,15 +149,15 @@ class TextChannel(discord.abc.Messageable, discord.abc.GuildChannel, Hashable):
except KeyError: except KeyError:
pass pass
else: else:
yield from self._move(position) yield from self._move(position, reason=reason)
self.position = position self.position = position
if options: if options:
data = yield from self._state.http.edit_channel(self.id, **options) data = yield from self._state.http.edit_channel(self.id, reason=reason, **options)
self._update(self.guild, data) self._update(self.guild, data)
@asyncio.coroutine @asyncio.coroutine
def delete_messages(self, messages): def delete_messages(self, messages, *, reason=None):
"""|coro| """|coro|
Deletes a list of messages. This is similar to :meth:`Message.delete` Deletes a list of messages. This is similar to :meth:`Message.delete`
@ -165,8 +167,10 @@ class TextChannel(discord.abc.Messageable, discord.abc.GuildChannel, Hashable):
Parameters Parameters
----------- -----------
messages : iterable of :class:`Message` messages: iterable of :class:`Message`
An iterable of messages denoting which ones to bulk delete. An iterable of messages denoting which ones to bulk delete.
reason: Optional[str]
The reason for bulk deleting these messages. Shows up on the audit log.
Raises Raises
------ ------
@ -186,10 +190,10 @@ class TextChannel(discord.abc.Messageable, discord.abc.GuildChannel, Hashable):
message_ids = [m.id for m in messages] message_ids = [m.id for m in messages]
channel = yield from self._get_channel() channel = yield from self._get_channel()
yield from self._state.http.delete_messages(channel.id, message_ids) yield from self._state.http.delete_messages(channel.id, message_ids, reason=reason)
@asyncio.coroutine @asyncio.coroutine
def purge(self, *, limit=100, check=None, before=None, after=None, around=None): def purge(self, *, limit=100, check=None, before=None, after=None, around=None, reason=None):
"""|coro| """|coro|
Purges a list of messages that meet the criteria given by the predicate Purges a list of messages that meet the criteria given by the predicate
@ -219,6 +223,8 @@ class TextChannel(discord.abc.Messageable, discord.abc.GuildChannel, Hashable):
Same as ``after`` in :meth:`history`. Same as ``after`` in :meth:`history`.
around around
Same as ``around`` in :meth:`history`. Same as ``around`` in :meth:`history`.
reason: Optional[str]
The reason for doing this action. Shows up on the audit log.
Raises Raises
------- -------
@ -262,17 +268,17 @@ class TextChannel(discord.abc.Messageable, discord.abc.GuildChannel, Hashable):
if count >= 2: if count >= 2:
# more than 2 messages -> bulk delete # more than 2 messages -> bulk delete
to_delete = ret[-count:] to_delete = ret[-count:]
yield from strategy(to_delete) yield from strategy(to_delete, reason=reason)
elif count == 1: elif count == 1:
# delete a single message # delete a single message
yield from ret[-1].delete() yield from ret[-1].delete(reason=reason)
return ret return ret
else: else:
if count == 100: if count == 100:
# we've reached a full 'queue' # we've reached a full 'queue'
to_delete = ret[-100:] to_delete = ret[-100:]
yield from strategy(to_delete) yield from strategy(to_delete, reason=reason)
count = 0 count = 0
yield from asyncio.sleep(1) yield from asyncio.sleep(1)
@ -283,7 +289,7 @@ class TextChannel(discord.abc.Messageable, discord.abc.GuildChannel, Hashable):
yield from ret[-1].delete() yield from ret[-1].delete()
elif count >= 2: elif count >= 2:
to_delete = ret[-count:] to_delete = ret[-count:]
yield from strategy(to_delete) yield from strategy(to_delete, reason=reason)
count = 0 count = 0
strategy = _single_delete_strategy strategy = _single_delete_strategy
@ -362,7 +368,7 @@ class VoiceChannel(discord.abc.Callable, discord.abc.GuildChannel, Hashable):
return ret return ret
@asyncio.coroutine @asyncio.coroutine
def edit(self, **options): def edit(self, *, reason=None, **options):
"""|coro| """|coro|
Edits the channel. Edits the channel.
@ -378,6 +384,8 @@ class VoiceChannel(discord.abc.Callable, discord.abc.GuildChannel, Hashable):
The new channel's user limit. The new channel's user limit.
position: int position: int
The new channel's position. The new channel's position.
reason: Optional[str]
The reason for editing this channel. Shows up on the audit log.
Raises Raises
------ ------
@ -392,11 +400,11 @@ class VoiceChannel(discord.abc.Callable, discord.abc.GuildChannel, Hashable):
except KeyError: except KeyError:
pass pass
else: else:
yield from self._move(position) yield from self._move(position, reason=reason)
self.position = position self.position = position
if options: if options:
data = yield from self._state.http.edit_channel(self.id, **options) data = yield from self._state.http.edit_channel(self.id, reason=reason, **options)
self._update(self.guild, data) self._update(self.guild, data)
class DMChannel(discord.abc.Messageable, Hashable): class DMChannel(discord.abc.Messageable, Hashable):

15
discord/emoji.py

@ -118,7 +118,7 @@ class Emoji(Hashable):
@asyncio.coroutine @asyncio.coroutine
def delete(self): def delete(self, *, reason=None):
"""|coro| """|coro|
Deletes the custom emoji. Deletes the custom emoji.
@ -128,6 +128,11 @@ class Emoji(Hashable):
Guild local emotes can only be deleted by user bots. Guild local emotes can only be deleted by user bots.
Parameters
-----------
reason: Optional[str]
The reason for deleting this emoji. Shows up on the audit log.
Raises Raises
------- -------
Forbidden Forbidden
@ -136,10 +141,10 @@ class Emoji(Hashable):
An error occurred deleting the emoji. An error occurred deleting the emoji.
""" """
yield from self._state.http.delete_custom_emoji(self.guild.id, self.id) yield from self._state.http.delete_custom_emoji(self.guild.id, self.id, reason=reason)
@asyncio.coroutine @asyncio.coroutine
def edit(self, *, name): def edit(self, *, name, reason=None):
"""|coro| """|coro|
Edits the custom emoji. Edits the custom emoji.
@ -153,6 +158,8 @@ class Emoji(Hashable):
----------- -----------
name: str name: str
The new emoji name. The new emoji name.
reason: Optional[str]
The reason for editing this emoji. Shows up on the audit log.
Raises Raises
------- -------
@ -162,4 +169,4 @@ class Emoji(Hashable):
An error occurred editing the emoji. An error occurred editing the emoji.
""" """
yield from self._state.http.edit_custom_emoji(self.guild.id, self.id, name=name) yield from self._state.http.edit_custom_emoji(self.guild.id, self.id, name=name, reason=reason)

62
discord/guild.py

@ -427,7 +427,7 @@ class Guild(Hashable):
return utils.find(pred, members) return utils.find(pred, members)
def _create_channel(self, name, overwrites, type): def _create_channel(self, name, overwrites, type, reason):
if overwrites is None: if overwrites is None:
overwrites = {} overwrites = {}
elif not isinstance(overwrites, dict): elif not isinstance(overwrites, dict):
@ -452,10 +452,10 @@ class Guild(Hashable):
perms.append(payload) perms.append(payload)
return self._state.http.create_channel(self.id, name, str(type), permission_overwrites=perms) return self._state.http.create_channel(self.id, name, str(type), permission_overwrites=perms, reason=reason)
@asyncio.coroutine @asyncio.coroutine
def create_text_channel(self, name, *, overwrites=None): def create_text_channel(self, name, *, overwrites=None, reason=None):
"""|coro| """|coro|
Creates a :class:`TextChannel` for the guild. Creates a :class:`TextChannel` for the guild.
@ -495,6 +495,8 @@ class Guild(Hashable):
A `dict` of target (either a role or a member) to A `dict` of target (either a role or a member) to
:class:`PermissionOverwrite` to apply upon creation of a channel. :class:`PermissionOverwrite` to apply upon creation of a channel.
Useful for creating secret channels. Useful for creating secret channels.
reason: Optional[str]
The reason for creating this channel. Shows up on the audit log.
Raises Raises
------- -------
@ -510,17 +512,17 @@ class Guild(Hashable):
:class:`TextChannel` :class:`TextChannel`
The channel that was just created. The channel that was just created.
""" """
data = yield from self._create_channel(name, overwrites, ChannelType.text) data = yield from self._create_channel(name, overwrites, ChannelType.text, reason=reason)
return TextChannel(state=self._state, guild=self, data=data) return TextChannel(state=self._state, guild=self, data=data)
@asyncio.coroutine @asyncio.coroutine
def create_voice_channel(self, name, *, overwrites=None): def create_voice_channel(self, name, *, overwrites=None, reason=None):
"""|coro| """|coro|
Same as :meth:`create_text_channel` except makes a Same as :meth:`create_text_channel` except makes a
:class:`VoiceChannel` instead. :class:`VoiceChannel` instead.
""" """
data = yield from self._create_channel(name, overwrites, ChannelType.voice) data = yield from self._create_channel(name, overwrites, ChannelType.voice, reason=reason)
return VoiceChannel(state=self._state, guild=self, data=data) return VoiceChannel(state=self._state, guild=self, data=data)
@asyncio.coroutine @asyncio.coroutine
@ -559,7 +561,7 @@ class Guild(Hashable):
yield from self._state.http.delete_guild(self.id) yield from self._state.http.delete_guild(self.id)
@asyncio.coroutine @asyncio.coroutine
def edit(self, **fields): def edit(self, *, reason=None, **fields):
"""|coro| """|coro|
Edits the guild. Edits the guild.
@ -590,6 +592,8 @@ class Guild(Hashable):
be owner of the guild to do this. be owner of the guild to do this.
verification_level: :class:`VerificationLevel` verification_level: :class:`VerificationLevel`
The new verification level for the guild. The new verification level for the guild.
reason: Optional[str]
The reason for editing this guild. Shows up on the audit log.
Raises Raises
------- -------
@ -642,7 +646,8 @@ class Guild(Hashable):
raise InvalidArgument('verification_level field must of type VerificationLevel') raise InvalidArgument('verification_level field must of type VerificationLevel')
fields['verification_level'] = level.value fields['verification_level'] = level.value
yield from self._state.http.edit_guild(self.id, **fields)
yield from self._state.http.edit_guild(self.id, reason=reason, **fields)
@asyncio.coroutine @asyncio.coroutine
@ -678,7 +683,7 @@ class Guild(Hashable):
for e in data] for e in data]
@asyncio.coroutine @asyncio.coroutine
def prune_members(self, *, days): def prune_members(self, *, days, reason=None):
"""|coro| """|coro|
Prunes the guild from its inactive members. Prunes the guild from its inactive members.
@ -696,6 +701,8 @@ class Guild(Hashable):
----------- -----------
days: int days: int
The number of days before counting as inactive. The number of days before counting as inactive.
reason: Optional[str]
The reason for doing this action. Shows up on the audit log.
Raises Raises
------- -------
@ -715,7 +722,7 @@ class Guild(Hashable):
if not isinstance(days, int): if not isinstance(days, int):
raise InvalidArgument('Expected int for ``days``, received {0.__class__.__name__} instead.'.format(days)) raise InvalidArgument('Expected int for ``days``, received {0.__class__.__name__} instead.'.format(days))
data = yield from self._state.http.prune_members(self.id, days) data = yield from self._state.http.prune_members(self.id, days, reason=reason)
return data['pruned'] return data['pruned']
@asyncio.coroutine @asyncio.coroutine
@ -784,7 +791,7 @@ class Guild(Hashable):
return result return result
@asyncio.coroutine @asyncio.coroutine
def create_invite(self, **fields): def create_invite(self, *, reason=None, **fields):
"""|coro| """|coro|
Creates an instant invite. Creates an instant invite.
@ -804,6 +811,8 @@ class Guild(Hashable):
Indicates if a unique invite URL should be created. Defaults to True. Indicates if a unique invite URL should be created. Defaults to True.
If this is set to False then it will return a previously created If this is set to False then it will return a previously created
invite. invite.
reason: Optional[str]
The reason for creating this invite. Shows up on the audit log.
Raises Raises
------- -------
@ -816,11 +825,11 @@ class Guild(Hashable):
The invite that was created. The invite that was created.
""" """
data = yield from self._state.http.create_invite(self.id, **fields) data = yield from self._state.http.create_invite(self.id, reason=reason, **fields)
return Invite.from_incomplete(data=data, state=self._state) return Invite.from_incomplete(data=data, state=self._state)
@asyncio.coroutine @asyncio.coroutine
def create_custom_emoji(self, *, name, image): def create_custom_emoji(self, *, name, image, reason=None):
"""|coro| """|coro|
Creates a custom :class:`Emoji` for the guild. Creates a custom :class:`Emoji` for the guild.
@ -839,6 +848,8 @@ class Guild(Hashable):
image: bytes image: bytes
The *bytes-like* object representing the image data to use. The *bytes-like* object representing the image data to use.
Only JPG and PNG images are supported. Only JPG and PNG images are supported.
reason: Optional[str]
The reason for creating this emoji. Shows up on the audit log.
Returns Returns
-------- --------
@ -854,11 +865,11 @@ class Guild(Hashable):
""" """
img = utils._bytes_to_base64_data(image) img = utils._bytes_to_base64_data(image)
data = yield from self._state.http.create_custom_emoji(self.id, name, img) data = yield from self._state.http.create_custom_emoji(self.id, name, img, reason=reason)
return self._state.store_emoji(self, data) return self._state.store_emoji(self, data)
@asyncio.coroutine @asyncio.coroutine
def create_role(self, **fields): def create_role(self, *, reason=None, **fields):
"""|coro| """|coro|
Creates a :class:`Role` for the guild. Creates a :class:`Role` for the guild.
@ -880,6 +891,8 @@ class Guild(Hashable):
mentionable: bool mentionable: bool
Indicates if the role should be mentionable by others. Indicates if the role should be mentionable by others.
Defaults to False. Defaults to False.
reason: Optional[str]
The reason for creating this role. Shows up on the audit log.
Returns Returns
-------- --------
@ -915,7 +928,7 @@ class Guild(Hashable):
if key not in valid_keys: if key not in valid_keys:
raise InvalidArgument('%r is not a valid field.' % key) raise InvalidArgument('%r is not a valid field.' % key)
data = yield from self._state.http.create_role(self.id, **fields) data = yield from self._state.http.create_role(self.id, reason=reason, **fields)
role = Role(guild=self, data=data, state=self._state) role = Role(guild=self, data=data, state=self._state)
# TODO: add to cache # TODO: add to cache
@ -979,7 +992,7 @@ class Guild(Hashable):
yield from self._state.http.ban(user.id, self.id, delete_message_days, reason=reason) yield from self._state.http.ban(user.id, self.id, delete_message_days, reason=reason)
@asyncio.coroutine @asyncio.coroutine
def unban(self, user): def unban(self, user, *, reason=None):
"""|coro| """|coro|
Unbans a user from the guild. Unbans a user from the guild.
@ -993,6 +1006,8 @@ class Guild(Hashable):
----------- -----------
user: :class:`abc.Snowflake` user: :class:`abc.Snowflake`
The user to unban. The user to unban.
reason: Optional[str]
The reason for doing this action. Shows up on the audit log.
Raises Raises
------- -------
@ -1001,7 +1016,7 @@ class Guild(Hashable):
HTTPException HTTPException
Unbanning failed. Unbanning failed.
""" """
yield from self._state.http.unban(user.id, self.id) yield from self._state.http.unban(user.id, self.id, reason=reason)
@asyncio.coroutine @asyncio.coroutine
def vanity_invite(self): def vanity_invite(self):
@ -1038,7 +1053,7 @@ class Guild(Hashable):
return Invite(state=self._state, data=payload) return Invite(state=self._state, data=payload)
@asyncio.coroutine @asyncio.coroutine
def change_vanity_invite(self, new_code): def change_vanity_invite(self, new_code, *, reason=None):
"""|coro| """|coro|
Changes the guild's special vanity invite. Changes the guild's special vanity invite.
@ -1048,6 +1063,13 @@ class Guild(Hashable):
You must have :attr:`Permissions.manage_guild` to use this as well. You must have :attr:`Permissions.manage_guild` to use this as well.
Parameters
-----------
new_code: str
The new vanity URL code.
reason: Optional[str]
The reason for changing the vanity invite. Shows up on the audit log.
Raises Raises
------- -------
Forbidden Forbidden
@ -1056,7 +1078,7 @@ class Guild(Hashable):
Setting the vanity invite failed. Setting the vanity invite failed.
""" """
yield from self._state.http.change_vanity_code(self.id, new_code) yield from self._state.http.change_vanity_code(self.id, new_code, reason=reason)
def ack(self): def ack(self):
"""|coro| """|coro|

127
discord/http.py

@ -125,6 +125,14 @@ class HTTPClient:
headers['Content-Type'] = 'application/json' headers['Content-Type'] = 'application/json'
kwargs['data'] = utils.to_json(kwargs.pop('json')) kwargs['data'] = utils.to_json(kwargs.pop('json'))
try:
reason = kwargs.pop('reason')
except KeyError:
pass
else:
if reason:
headers['X-Audit-Log-Reason'] = reason
kwargs['headers'] = headers kwargs['headers'] = headers
if not self._global_over.is_set(): if not self._global_over.is_set():
@ -336,18 +344,18 @@ class HTTPClient:
def ack_guild(self, guild_id): def ack_guild(self, guild_id):
return self.request(Route('POST', '/guilds/{guild_id}/ack', guild_id=guild_id)) return self.request(Route('POST', '/guilds/{guild_id}/ack', guild_id=guild_id))
def delete_message(self, channel_id, message_id): def delete_message(self, channel_id, message_id, *, reason=None):
r = Route('DELETE', '/channels/{channel_id}/messages/{message_id}', channel_id=channel_id, r = Route('DELETE', '/channels/{channel_id}/messages/{message_id}', channel_id=channel_id,
message_id=message_id) message_id=message_id)
return self.request(r) return self.request(r, reason=reason)
def delete_messages(self, channel_id, message_ids): def delete_messages(self, channel_id, message_ids, *, reason=None):
r = Route('POST', '/channels/{channel_id}/messages/bulk_delete', channel_id=channel_id) r = Route('POST', '/channels/{channel_id}/messages/bulk_delete', channel_id=channel_id)
payload = { payload = {
'messages': message_ids 'messages': message_ids
} }
return self.request(r, json=payload) return self.request(r, json=payload, reason=reason)
def edit_message(self, message_id, channel_id, **fields): def edit_message(self, message_id, channel_id, **fields):
r = Route('PATCH', '/channels/{channel_id}/messages/{message_id}', channel_id=channel_id, r = Route('PATCH', '/channels/{channel_id}/messages/{message_id}', channel_id=channel_id,
@ -426,11 +434,11 @@ class HTTPClient:
return self.request(r, params=params) return self.request(r, params=params)
def unban(self, user_id, guild_id): def unban(self, user_id, guild_id, *, reason=None):
r = Route('DELETE', '/guilds/{guild_id}/bans/{user_id}', guild_id=guild_id, user_id=user_id) r = Route('DELETE', '/guilds/{guild_id}/bans/{user_id}', guild_id=guild_id, user_id=user_id)
return self.request(r) return self.request(r, reason=reason)
def guild_voice_state(self, user_id, guild_id, *, mute=None, deafen=None): def guild_voice_state(self, user_id, guild_id, *, mute=None, deafen=None, reason=None):
r = Route('PATCH', '/guilds/{guild_id}/members/{user_id}', guild_id=guild_id, user_id=user_id) r = Route('PATCH', '/guilds/{guild_id}/members/{user_id}', guild_id=guild_id, user_id=user_id)
payload = {} payload = {}
if mute is not None: if mute is not None:
@ -439,7 +447,7 @@ class HTTPClient:
if deafen is not None: if deafen is not None:
payload['deaf'] = deafen payload['deaf'] = deafen
return self.request(r, json=payload) return self.request(r, json=payload, reason=reason)
def edit_profile(self, password, username, avatar, **fields): def edit_profile(self, password, username, avatar, **fields):
payload = { payload = {
@ -456,38 +464,40 @@ class HTTPClient:
return self.request(Route('PATCH', '/users/@me'), json=payload) return self.request(Route('PATCH', '/users/@me'), json=payload)
def change_my_nickname(self, guild_id, nickname): def change_my_nickname(self, guild_id, nickname, *, reason=None):
r = Route('PATCH', '/guilds/{guild_id}/members/@me/nick', guild_id=guild_id)
payload = { payload = {
'nick': nickname 'nick': nickname
} }
return self.request(Route('PATCH', '/guilds/{guild_id}/members/@me/nick', guild_id=guild_id), json=payload) return self.request(r, json=payload, reason=reason)
def change_nickname(self, guild_id, user_id, nickname): def change_nickname(self, guild_id, user_id, nickname, *, reason=None):
r = Route('PATCH', '/guilds/{guild_id}/members/{user_id}', guild_id=guild_id, user_id=user_id) r = Route('PATCH', '/guilds/{guild_id}/members/{user_id}', guild_id=guild_id, user_id=user_id)
payload = { payload = {
'nick': nickname 'nick': nickname
} }
return self.request(r, json=payload) return self.request(r, json=payload, reason=reason)
def edit_member(self, guild_id, user_id, **fields): def edit_member(self, guild_id, user_id, *, reason=None, **fields):
r = Route('PATCH', '/guilds/{guild_id}/members/{user_id}', guild_id=guild_id, user_id=user_id) r = Route('PATCH', '/guilds/{guild_id}/members/{user_id}', guild_id=guild_id, user_id=user_id)
return self.request(r, json=fields) return self.request(r, json=fields, reason=reason)
# Channel management # Channel management
def edit_channel(self, channel_id, **options): def edit_channel(self, channel_id, *, reason=None, **options):
r = Route('PATCH', '/channels/{channel_id}', channel_id=channel_id)
valid_keys = ('name', 'topic', 'bitrate', 'user_limit', 'position') valid_keys = ('name', 'topic', 'bitrate', 'user_limit', 'position')
payload = { payload = {
k: v for k, v in options.items() if k in valid_keys k: v for k, v in options.items() if k in valid_keys
} }
return self.request(Route('PATCH', '/channels/{channel_id}', channel_id=channel_id), json=payload) return self.request(r, reason=reason, json=payload)
def move_channel_position(self, guild_id, positions): def move_channel_position(self, guild_id, positions, *, reason=None):
r = Route('PATCH', '/guilds/{guild_id}/channels', guild_id=guild_id) r = Route('PATCH', '/guilds/{guild_id}/channels', guild_id=guild_id)
return self.request(r, json=positions) return self.request(r, json=positions, reason=reason)
def create_channel(self, guild_id, name, channe_type, permission_overwrites=None): def create_channel(self, guild_id, name, channe_type, permission_overwrites=None, *, reason=None):
payload = { payload = {
'name': name, 'name': name,
'type': channe_type 'type': channe_type
@ -496,10 +506,10 @@ class HTTPClient:
if permission_overwrites is not None: if permission_overwrites is not None:
payload['permission_overwrites'] = permission_overwrites payload['permission_overwrites'] = permission_overwrites
return self.request(Route('POST', '/guilds/{guild_id}/channels', guild_id=guild_id), json=payload) return self.request(Route('POST', '/guilds/{guild_id}/channels', guild_id=guild_id), json=payload, reason=reason)
def delete_channel(self, channel_id): def delete_channel(self, channel_id, *, reason=None):
return self.request(Route('DELETE', '/channels/{channel_id}', channel_id=channel_id)) return self.request(Route('DELETE', '/channels/{channel_id}', channel_id=channel_id), reason=reason)
# Guild management # Guild management
@ -518,7 +528,7 @@ class HTTPClient:
return self.request(Route('POST', '/guilds'), json=payload) return self.request(Route('POST', '/guilds'), json=payload)
def edit_guild(self, guild_id, **fields): def edit_guild(self, guild_id, *, reason=None, **fields):
valid_keys = ('name', 'region', 'icon', 'afk_timeout', 'owner_id', valid_keys = ('name', 'region', 'icon', 'afk_timeout', 'owner_id',
'afk_channel_id', 'splash', 'verification_level') 'afk_channel_id', 'splash', 'verification_level')
@ -526,7 +536,7 @@ class HTTPClient:
k: v for k, v in fields.items() if k in valid_keys k: v for k, v in fields.items() if k in valid_keys
} }
return self.request(Route('PATCH', '/guilds/{guild_id}', guild_id=guild_id), json=payload) return self.request(Route('PATCH', '/guilds/{guild_id}', guild_id=guild_id), json=payload, reason=reason)
def get_bans(self, guild_id): def get_bans(self, guild_id):
return self.request(Route('GET', '/guilds/{guild_id}/bans', guild_id=guild_id)) return self.request(Route('GET', '/guilds/{guild_id}/bans', guild_id=guild_id))
@ -534,15 +544,15 @@ class HTTPClient:
def get_vanity_code(self, guild_id): def get_vanity_code(self, guild_id):
return self.request(Route('GET', '/guilds/{guild_id}/vanity-url', guild_id=guild_id)) return self.request(Route('GET', '/guilds/{guild_id}/vanity-url', guild_id=guild_id))
def change_vanity_code(self, guild_id, code): def change_vanity_code(self, guild_id, code, *, reason=None):
payload = { 'code': code } payload = { 'code': code }
return self.request(Route('PATCH', '/guilds/{guild_id}/vanity-url', guild_id=guild_id), json=payload) return self.request(Route('PATCH', '/guilds/{guild_id}/vanity-url', guild_id=guild_id), json=payload, reason=reason)
def prune_members(self, guild_id, days): def prune_members(self, guild_id, days, *, reason=None):
params = { params = {
'days': days 'days': days
} }
return self.request(Route('POST', '/guilds/{guild_id}/prune', guild_id=guild_id), params=params) return self.request(Route('POST', '/guilds/{guild_id}/prune', guild_id=guild_id), params=params, reason=reason)
def estimate_pruned_members(self, guild_id, days): def estimate_pruned_members(self, guild_id, days):
params = { params = {
@ -550,24 +560,25 @@ class HTTPClient:
} }
return self.request(Route('GET', '/guilds/{guild_id}/prune', guild_id=guild_id), params=params) return self.request(Route('GET', '/guilds/{guild_id}/prune', guild_id=guild_id), params=params)
def create_custom_emoji(self, guild_id, name, image): def create_custom_emoji(self, guild_id, name, image, *, reason=None):
payload = { payload = {
'name': name, 'name': name,
'image': image 'image': image
} }
r = Route('POST', '/guilds/{guild_id}/emojis', guild_id=guild_id) r = Route('POST', '/guilds/{guild_id}/emojis', guild_id=guild_id)
return self.request(r, json=payload) return self.request(r, json=payload, reason=reason)
def delete_custom_emoji(self, guild_id, emoji_id): def delete_custom_emoji(self, guild_id, emoji_id, *, reason=None):
return self.request(Route('DELETE', '/guilds/{guild_id}/emojis/{emoji_id}', guild_id=guild_id, emoji_id=emoji_id)) r = Route('DELETE', '/guilds/{guild_id}/emojis/{emoji_id}', guild_id=guild_id, emoji_id=emoji_id)
return self.request(r, reason=reason)
def edit_custom_emoji(self, guild_id, emoji_id, *, name): def edit_custom_emoji(self, guild_id, emoji_id, *, name, reason=None):
payload = { payload = {
'name': name 'name': name
} }
r = Route('PATCH', '/guilds/{guild_id}/emojis/{emoji_id}', guild_id=guild_id, emoji_id=emoji_id) r = Route('PATCH', '/guilds/{guild_id}/emojis/{emoji_id}', guild_id=guild_id, emoji_id=emoji_id)
return self.request(r, json=payload) return self.request(r, json=payload, reason=reason)
def get_audit_logs(self, guild_id, limit=100, before=None, after=None, user_id=None, action_type=None): def get_audit_logs(self, guild_id, limit=100, before=None, after=None, user_id=None, action_type=None):
params = { 'limit': limit } params = { 'limit': limit }
@ -585,7 +596,7 @@ class HTTPClient:
# Invite management # Invite management
def create_invite(self, channel_id, **options): def create_invite(self, channel_id, *, reason=None, **options):
r = Route('POST', '/channels/{channel_id}/invites', channel_id=channel_id) r = Route('POST', '/channels/{channel_id}/invites', channel_id=channel_id)
payload = { payload = {
'max_age': options.get('max_age', 0), 'max_age': options.get('max_age', 0),
@ -594,7 +605,7 @@ class HTTPClient:
'unique': options.get('unique', True) 'unique': options.get('unique', True)
} }
return self.request(r, json=payload) return self.request(r, reason=reason, json=payload)
def get_invite(self, invite_id): def get_invite(self, invite_id):
return self.request(Route('GET', '/invite/{invite_id}', invite_id=invite_id)) return self.request(Route('GET', '/invite/{invite_id}', invite_id=invite_id))
@ -605,45 +616,45 @@ class HTTPClient:
def invites_from_channel(self, channel_id): def invites_from_channel(self, channel_id):
return self.request(Route('GET', '/channels/{channel_id}/invites', channel_id=channel_id)) return self.request(Route('GET', '/channels/{channel_id}/invites', channel_id=channel_id))
def delete_invite(self, invite_id): def delete_invite(self, invite_id, *, reason=None):
return self.request(Route('DELETE', '/invite/{invite_id}', invite_id=invite_id)) return self.request(Route('DELETE', '/invite/{invite_id}', invite_id=invite_id), reason=reason)
# Role management # Role management
def edit_role(self, guild_id, role_id, **fields): def edit_role(self, guild_id, role_id, *, reason=None, **fields):
r = Route('PATCH', '/guilds/{guild_id}/roles/{role_id}', guild_id=guild_id, role_id=role_id) r = Route('PATCH', '/guilds/{guild_id}/roles/{role_id}', guild_id=guild_id, role_id=role_id)
valid_keys = ('name', 'permissions', 'color', 'hoist', 'mentionable') valid_keys = ('name', 'permissions', 'color', 'hoist', 'mentionable')
payload = { payload = {
k: v for k, v in fields.items() if k in valid_keys k: v for k, v in fields.items() if k in valid_keys
} }
return self.request(r, json=payload) return self.request(r, json=payload, reason=reason)
def delete_role(self, guild_id, role_id): def delete_role(self, guild_id, role_id, *, reason=None):
r = Route('DELETE', '/guilds/{guild_id}/roles/{role_id}', guild_id=guild_id, role_id=role_id) r = Route('DELETE', '/guilds/{guild_id}/roles/{role_id}', guild_id=guild_id, role_id=role_id)
return self.request(r) return self.request(r, reason=reason)
def replace_roles(self, user_id, guild_id, role_ids): def replace_roles(self, user_id, guild_id, role_ids, *, reason=None):
return self.edit_member(guild_id=guild_id, user_id=user_id, roles=role_ids) return self.edit_member(guild_id=guild_id, user_id=user_id, roles=role_ids, reason=reason)
def create_role(self, guild_id, **fields): def create_role(self, guild_id, *, reason=None, **fields):
r = Route('POST', '/guilds/{guild_id}/roles', guild_id=guild_id) r = Route('POST', '/guilds/{guild_id}/roles', guild_id=guild_id)
return self.request(r, json=fields) return self.request(r, json=fields, reason=reason)
def move_role_position(self, guild_id, positions): def move_role_position(self, guild_id, positions, *, reason=None):
r = Route('PATCH', '/guilds/{guild_id}/roles', guild_id=guild_id) r = Route('PATCH', '/guilds/{guild_id}/roles', guild_id=guild_id)
return self.request(r, json=positions) return self.request(r, json=positions, reason=reason)
def add_role(self, guild_id, user_id, role_id): def add_role(self, guild_id, user_id, role_id, *, reason=None):
r = Route('PUT', '/guilds/{guild_id}/members/{user_id}/roles/{role_id}', r = Route('PUT', '/guilds/{guild_id}/members/{user_id}/roles/{role_id}',
guild_id=guild_id, user_id=user_id, role_id=role_id) guild_id=guild_id, user_id=user_id, role_id=role_id)
return self.request(r) return self.request(r, reason=reason)
def remove_role(self, guild_id, user_id, role_id): def remove_role(self, guild_id, user_id, role_id, *, reason=None):
r = Route('DELETE', '/guilds/{guild_id}/members/{user_id}/roles/{role_id}', r = Route('DELETE', '/guilds/{guild_id}/members/{user_id}/roles/{role_id}',
guild_id=guild_id, user_id=user_id, role_id=role_id) guild_id=guild_id, user_id=user_id, role_id=role_id)
return self.request(r) return self.request(r, reason=reason)
def edit_channel_permissions(self, channel_id, target, allow, deny, type): def edit_channel_permissions(self, channel_id, target, allow, deny, type, *, reason=None):
payload = { payload = {
'id': target, 'id': target,
'allow': allow, 'allow': allow,
@ -651,16 +662,16 @@ class HTTPClient:
'type': type 'type': type
} }
r = Route('PUT', '/channels/{channel_id}/permissions/{target}', channel_id=channel_id, target=target) r = Route('PUT', '/channels/{channel_id}/permissions/{target}', channel_id=channel_id, target=target)
return self.request(r, json=payload) return self.request(r, json=payload, reason=reason)
def delete_channel_permissions(self, channel_id, target): def delete_channel_permissions(self, channel_id, target, *, reason=None):
r = Route('DELETE', '/channels/{channel_id}/permissions/{target}', channel_id=channel_id, target=target) r = Route('DELETE', '/channels/{channel_id}/permissions/{target}', channel_id=channel_id, target=target)
return self.request(r) return self.request(r, reason=reason)
# Voice management # Voice management
def move_member(self, user_id, guild_id, channel_id): def move_member(self, user_id, guild_id, channel_id, *, reason=None):
return self.edit_member(guild_id=guild_id, user_id=user_id, channel_id=channel_id) return self.edit_member(guild_id=guild_id, user_id=user_id, channel_id=channel_id, reason=reason)
# Relationship related # Relationship related

9
discord/invite.py

@ -147,11 +147,16 @@ class Invite(Hashable):
yield from self._state.http.accept_invite(self.code) yield from self._state.http.accept_invite(self.code)
@asyncio.coroutine @asyncio.coroutine
def delete(self): def delete(self, *, reason=None):
"""|coro| """|coro|
Revokes the instant invite. Revokes the instant invite.
Parameters
-----------
reason: Optional[str]
The reason for deleting this invite. Shows up on the audit log.
Raises Raises
------- -------
Forbidden Forbidden
@ -162,4 +167,4 @@ class Invite(Hashable):
Revoking the invite failed. Revoking the invite failed.
""" """
yield from self._state.http.delete_invite(self.code) yield from self._state.http.delete_invite(self.code, reason=reason)

30
discord/member.py

@ -349,12 +349,12 @@ class Member(discord.abc.Messageable):
yield from self.guild.ban(self, **kwargs) yield from self.guild.ban(self, **kwargs)
@asyncio.coroutine @asyncio.coroutine
def unban(self): def unban(self, *, reason=None):
"""|coro| """|coro|
Unbans this member. Equivalent to :meth:`Guild.unban` Unbans this member. Equivalent to :meth:`Guild.unban`
""" """
yield from self.guild.unban(self) yield from self.guild.unban(self, reason=reason)
@asyncio.coroutine @asyncio.coroutine
def kick(self, *, reason=None): def kick(self, *, reason=None):
@ -365,7 +365,7 @@ class Member(discord.abc.Messageable):
yield from self.guild.kick(self, reason=reason) yield from self.guild.kick(self, reason=reason)
@asyncio.coroutine @asyncio.coroutine
def edit(self, **fields): def edit(self, *, reason=None, **fields):
"""|coro| """|coro|
Edits the member's data. Edits the member's data.
@ -400,6 +400,8 @@ class Member(discord.abc.Messageable):
The member's new list of roles. This *replaces* the roles. The member's new list of roles. This *replaces* the roles.
voice_channel: :class:`VoiceChannel` voice_channel: :class:`VoiceChannel`
The voice channel to move the member to. The voice channel to move the member to.
reason: Optional[str]
The reason for editing this member. Shows up on the audit log.
Raises Raises
------- -------
@ -420,7 +422,7 @@ class Member(discord.abc.Messageable):
else: else:
nick = nick if nick else '' nick = nick if nick else ''
if self._state.self_id == self.id: if self._state.self_id == self.id:
yield from http.change_my_nickname(guild_id, nick) yield from http.change_my_nickname(guild_id, nick, reason=reason)
else: else:
payload['nick'] = nick payload['nick'] = nick
@ -446,12 +448,12 @@ class Member(discord.abc.Messageable):
else: else:
payload['roles'] = tuple(r.id for r in roles) payload['roles'] = tuple(r.id for r in roles)
yield from http.edit_member(guild_id, self.id, **payload) yield from http.edit_member(guild_id, self.id, reason=reason, **payload)
# TODO: wait for WS event for modify-in-place behaviour # TODO: wait for WS event for modify-in-place behaviour
@asyncio.coroutine @asyncio.coroutine
def move_to(self, channel): def move_to(self, channel, *, reason=None):
"""|coro| """|coro|
Moves a member to a new voice channel (they must be connected first). Moves a member to a new voice channel (they must be connected first).
@ -465,11 +467,13 @@ class Member(discord.abc.Messageable):
----------- -----------
channel: :class:`VoiceChannel` channel: :class:`VoiceChannel`
The new voice channel to move the member to. The new voice channel to move the member to.
reason: Optional[str]
The reason for doing this action. Shows up on the audit log.
""" """
yield from self.edit(voice_channel=channel) yield from self.edit(voice_channel=channel, reason=reason)
@asyncio.coroutine @asyncio.coroutine
def add_roles(self, *roles): def add_roles(self, *roles, reason=None):
"""|coro| """|coro|
Gives the member a number of :class:`Role`\s. Gives the member a number of :class:`Role`\s.
@ -481,6 +485,8 @@ class Member(discord.abc.Messageable):
----------- -----------
\*roles \*roles
An argument list of :class:`Role`\s to give the member. An argument list of :class:`Role`\s to give the member.
reason: Optional[str]
The reason for adding these roles. Shows up on the audit log.
Raises Raises
------- -------
@ -491,10 +497,10 @@ class Member(discord.abc.Messageable):
""" """
new_roles = utils._unique(r for s in (self.roles[1:], roles) for r in s) new_roles = utils._unique(r for s in (self.roles[1:], roles) for r in s)
yield from self.edit(roles=new_roles) yield from self.edit(roles=new_roles, reason=reason)
@asyncio.coroutine @asyncio.coroutine
def remove_roles(self, *roles): def remove_roles(self, *roles, reason=None):
"""|coro| """|coro|
Removes :class:`Role`\s from this member. Removes :class:`Role`\s from this member.
@ -506,6 +512,8 @@ class Member(discord.abc.Messageable):
----------- -----------
\*roles \*roles
An argument list of :class:`Role`\s to remove from the member. An argument list of :class:`Role`\s to remove from the member.
reason: Optional[str]
The reason for removing these roles. Shows up on the audit log.
Raises Raises
------- -------
@ -522,4 +530,4 @@ class Member(discord.abc.Messageable):
except ValueError: except ValueError:
pass pass
yield from self.edit(roles=new_roles) yield from self.edit(roles=new_roles, reason=reason)

9
discord/message.py

@ -407,7 +407,7 @@ class Message:
return '{0.author.name} started a call \N{EM DASH} Join the call.'.format(self) return '{0.author.name} started a call \N{EM DASH} Join the call.'.format(self)
@asyncio.coroutine @asyncio.coroutine
def delete(self): def delete(self, *, reason=None):
"""|coro| """|coro|
Deletes the message. Deletes the message.
@ -416,6 +416,11 @@ class Message:
delete other people's messages, you need the :attr:`Permissions.manage_messages` delete other people's messages, you need the :attr:`Permissions.manage_messages`
permission. permission.
Parameters
------------
reason: Optional[str]
The reason for deleting this message. Shows up on the audit log.
Raises Raises
------ ------
Forbidden Forbidden
@ -423,7 +428,7 @@ class Message:
HTTPException HTTPException
Deleting the message failed. Deleting the message failed.
""" """
yield from self._state.http.delete_message(self.channel.id, self.id) yield from self._state.http.delete_message(self.channel.id, self.id, reason=reason)
@asyncio.coroutine @asyncio.coroutine
def edit(self, **fields): def edit(self, **fields):

21
discord/role.py

@ -160,7 +160,7 @@ class Role(Hashable):
return [member for member in all_members if self in member.roles] return [member for member in all_members if self in member.roles]
@asyncio.coroutine @asyncio.coroutine
def _move(self, position): def _move(self, position, reason):
if position <= 0: if position <= 0:
raise InvalidArgument("Cannot move role to position 0 or below") raise InvalidArgument("Cannot move role to position 0 or below")
@ -184,10 +184,10 @@ class Role(Hashable):
roles.append(self.id) roles.append(self.id)
payload = [{"id": z[0], "position": z[1]} for z in zip(roles, change_range)] payload = [{"id": z[0], "position": z[1]} for z in zip(roles, change_range)]
yield from http.move_role_position(self.guild.id, payload) yield from http.move_role_position(self.guild.id, payload, reason=reason)
@asyncio.coroutine @asyncio.coroutine
def edit(self, **fields): def edit(self, *, reason=None, **fields):
"""|coro| """|coro|
Edits the role. Edits the role.
@ -212,6 +212,8 @@ class Role(Hashable):
position: int position: int
The new role's position. This must be below your top role's The new role's position. This must be below your top role's
position or it will fail. position or it will fail.
reason: Optional[str]
The reason for editing this role. Shows up on the audit log.
Raises Raises
------- -------
@ -226,7 +228,7 @@ class Role(Hashable):
position = fields.get('position') position = fields.get('position')
if position is not None: if position is not None:
yield from self._move(position) yield from self._move(position, reason=reason)
self.position = position self.position = position
try: try:
@ -242,11 +244,11 @@ class Role(Hashable):
'mentionable': fields.get('mentionable', self.mentionable) 'mentionable': fields.get('mentionable', self.mentionable)
} }
data = yield from self._state.http.edit_role(self.guild.id, self.id, **payload) data = yield from self._state.http.edit_role(self.guild.id, self.id, reason=reason, **payload)
self._update(data) self._update(data)
@asyncio.coroutine @asyncio.coroutine
def delete(self): def delete(self, *, reason=None):
"""|coro| """|coro|
Deletes the role. Deletes the role.
@ -254,6 +256,11 @@ class Role(Hashable):
You must have the :attr:`Permissions.manage_roles` permission to You must have the :attr:`Permissions.manage_roles` permission to
use this. use this.
Parameters
-----------
reason: Optional[str]
The reason for deleting this role. Shows up on the audit log.
Raises Raises
-------- --------
Forbidden Forbidden
@ -262,4 +269,4 @@ class Role(Hashable):
Deleting the role failed. Deleting the role failed.
""" """
yield from self._state.http.delete_role(self.guild.id, self.id) yield from self._state.http.delete_role(self.guild.id, self.id, reason=reason)

Loading…
Cancel
Save