aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--discord/abc.py57
-rw-r--r--discord/channel.py27
-rw-r--r--discord/ext/commands/context.py19
-rw-r--r--discord/reaction.py2
4 files changed, 62 insertions, 43 deletions
diff --git a/discord/abc.py b/discord/abc.py
index d50966e4..05f4eb70 100644
--- a/discord/abc.py
+++ b/discord/abc.py
@@ -466,18 +466,22 @@ class GuildChannel:
raise InvalidArgument('Invalid overwrite type provided.')
-class MessageChannel(metaclass=abc.ABCMeta):
+class Messageable(metaclass=abc.ABCMeta):
__slots__ = ()
@abc.abstractmethod
- def _get_destination(self):
+ def _get_channel(self):
+ raise NotImplementedError
+
+ @abc.abstractmethod
+ def _get_guild_id(self):
raise NotImplementedError
@asyncio.coroutine
def send(self, content=None, *, tts=False, embed=None, file=None, filename=None, delete_after=None):
"""|coro|
- Sends a message to the channel with the content given.
+ Sends a message to the destination with the content given.
The content must be a type that can convert to a string through ``str(content)``.
If the content is set to ``None`` (the default), then the ``embed`` parameter must
@@ -532,7 +536,8 @@ class MessageChannel(metaclass=abc.ABCMeta):
The message that was sent.
"""
- channel_id, guild_id = self._get_destination()
+ channel = self._get_channel()
+ guild_id = self._get_guild_id()
state = self._state
content = str(content) if content else None
if embed is not None:
@@ -547,12 +552,12 @@ class MessageChannel(metaclass=abc.ABCMeta):
except TypeError:
buffer = file
- data = yield from state.http.send_file(channel_id, buffer, guild_id=guild_id, filename=filename,
+ data = yield from state.http.send_file(channel.id, buffer, guild_id=guild_id, filename=filename,
content=content, tts=tts, embed=embed)
else:
- data = yield from state.http.send_message(channel_id, content, guild_id=guild_id, tts=tts, embed=embed)
+ data = yield from state.http.send_message(channel.id, content, guild_id=guild_id, tts=tts, embed=embed)
- ret = Message(channel=self, state=state, data=data)
+ ret = Message(channel=channel, state=state, data=data)
if delete_after is not None:
@asyncio.coroutine
def delete():
@@ -565,22 +570,27 @@ class MessageChannel(metaclass=abc.ABCMeta):
return ret
@asyncio.coroutine
- def send_typing(self):
+ def trigger_typing(self):
"""|coro|
- Send a *typing* status to the channel.
+ Triggers a *typing* indicator to the destination.
- *Typing* status will go away after 10 seconds, or after a message is sent.
+ *Typing* indicator will go away after 10 seconds, or after a message is sent.
"""
- channel_id, _ = self._get_destination()
- yield from self._state.http.send_typing(channel_id)
+ channel = self._get_channel()
+ yield from self._state.http.send_typing(channel.id)
def typing(self):
"""Returns a context manager that allows you to type for an indefinite period of time.
This is useful for denoting long computations in your bot.
+ .. note::
+
+ This is both a regular context manager and an async context manager.
+ This means that both ``with`` and ``async with`` work with this.
+
Example Usage: ::
with channel.typing():
@@ -588,13 +598,13 @@ class MessageChannel(metaclass=abc.ABCMeta):
await channel.send_message('done!')
"""
- return Typing(self)
+ return Typing(self._get_channel())
@asyncio.coroutine
def get_message(self, id):
"""|coro|
- Retrieves a single :class:`Message` from a channel.
+ Retrieves a single :class:`Message` from the destination.
This can only be used by bot accounts.
@@ -618,8 +628,9 @@ class MessageChannel(metaclass=abc.ABCMeta):
Retrieving the message failed.
"""
- data = yield from self._state.http.get_message(self.id, id)
- return Message(channel=self, state=self._state, data=data)
+ channel = self._get_channel()
+ data = yield from self._state.http.get_message(channel.id, id)
+ return Message(channel=channel, state=self._state, data=data)
@asyncio.coroutine
def delete_messages(self, messages):
@@ -651,9 +662,10 @@ class MessageChannel(metaclass=abc.ABCMeta):
raise ClientException('Can only delete messages in the range of [2, 100]')
message_ids = [m.id for m in messages]
- channel_id, guild_id = self._get_destination()
+ channel = self._get_channel()
+ guild_id = self._get_guild_id()
- yield from self._state.http.delete_messages(channel_id, message_ids, guild_id)
+ yield from self._state.http.delete_messages(channel.id, message_ids, guild_id)
@asyncio.coroutine
def pins(self):
@@ -667,12 +679,13 @@ class MessageChannel(metaclass=abc.ABCMeta):
Retrieving the pinned messages failed.
"""
+ channel = self._get_channel()
state = self._state
- data = yield from state.http.pins_from(self.id)
- return [Message(channel=self, state=state, data=m) for m in data]
+ data = yield from state.http.pins_from(channel.id)
+ return [Message(channel=channel, state=state, data=m) for m in data]
def history(self, *, limit=100, before=None, after=None, around=None, reverse=None):
- """Return an async iterator that enables receiving the channel's message history.
+ """Return an async iterator that enables receiving the destination's message history.
You must have Read Message History permissions to use this.
@@ -734,7 +747,7 @@ class MessageChannel(metaclass=abc.ABCMeta):
if message.author == client.user:
counter += 1
"""
- return LogsFromIterator(self, limit=limit, before=before, after=after, around=around, reverse=reverse)
+ return LogsFromIterator(self._get_channel(), limit=limit, before=before, after=after, around=around, reverse=reverse)
@asyncio.coroutine
def purge(self, *, limit=100, check=None, before=None, after=None, around=None):
diff --git a/discord/channel.py b/discord/channel.py
index 80ecdaab..5be646cb 100644
--- a/discord/channel.py
+++ b/discord/channel.py
@@ -38,7 +38,7 @@ import asyncio
__all__ = ('TextChannel', 'VoiceChannel', 'DMChannel', 'GroupChannel', '_channel_factory')
-class TextChannel(discord.abc.MessageChannel, discord.abc.GuildChannel, Hashable):
+class TextChannel(discord.abc.Messageable, discord.abc.GuildChannel, Hashable):
"""Represents a Discord guild text channel.
Supported Operations:
@@ -88,8 +88,11 @@ class TextChannel(discord.abc.MessageChannel, discord.abc.GuildChannel, Hashable
self.position = data['position']
self._fill_overwrites(data)
- def _get_destination(self):
- return self.id, self.guild.id
+ def _get_channel(self):
+ return self
+
+ def _get_guild_id(self):
+ return self.guild.id
@asyncio.coroutine
def edit(self, **options):
@@ -224,7 +227,7 @@ class VoiceChannel(discord.abc.GuildChannel, Hashable):
data = yield from self._state.http.edit_channel(self.id, **options)
self._update(self.guild, data)
-class DMChannel(discord.abc.MessageChannel, Hashable):
+class DMChannel(discord.abc.Messageable, Hashable):
"""Represents a Discord direct message channel.
Supported Operations:
@@ -259,8 +262,11 @@ class DMChannel(discord.abc.MessageChannel, Hashable):
self.me = me
self.id = int(data['id'])
- def _get_destination(self):
- return self.id, None
+ def _get_channel(self):
+ return self
+
+ def _get_guild_id(self):
+ return None
def __str__(self):
return 'Direct Message with %s' % self.recipient
@@ -302,7 +308,7 @@ class DMChannel(discord.abc.MessageChannel, Hashable):
base.manage_messages = False
return base
-class GroupChannel(discord.abc.MessageChannel, Hashable):
+class GroupChannel(discord.abc.Messageable, Hashable):
"""Represents a Discord group channel.
Supported Operations:
@@ -354,8 +360,11 @@ class GroupChannel(discord.abc.MessageChannel, Hashable):
else:
self.owner = discord.utils.find(lambda u: u.id == owner_id, self.recipients)
- def _get_destination(self):
- return self.id, None
+ def _get_channel(self):
+ return self
+
+ def _get_guild_id(self):
+ return None
def __str__(self):
if self.name:
diff --git a/discord/ext/commands/context.py b/discord/ext/commands/context.py
index efaa5b43..ff78c562 100644
--- a/discord/ext/commands/context.py
+++ b/discord/ext/commands/context.py
@@ -27,14 +27,14 @@ import asyncio
import discord.abc
import discord.utils
-class Context(discord.abc.MessageChannel):
+class Context(discord.abc.Messageable):
"""Represents the context in which a command is being invoked under.
This class contains a lot of meta data to help you understand more about
the invocation context. This class is not created manually and is instead
passed around to commands by passing in :attr:`Command.pass_context`.
- This class implements the :class:`abc.MessageChannel` ABC.
+ This class implements the :class:`abc.Messageable` ABC.
Attributes
-----------
@@ -117,8 +117,12 @@ class Context(discord.abc.MessageChannel):
ret = yield from command.callback(*arguments, **kwargs)
return ret
- def _get_destination(self):
- return self.channel.id, getattr(self.guild, 'id', None)
+ def _get_channel(self):
+ return self.channel
+
+ def _get_guild_id(self):
+ g = self.guild
+ return g.id if g is not None else None
@property
def cog(self):
@@ -129,13 +133,6 @@ class Context(discord.abc.MessageChannel):
return self.command.instance
@discord.utils.cached_property
- def id(self):
- # we need this to meet MessageChannel abc
- # it is purposefully undocumented because it makes no logistic sense
- # outside of providing the sugar of the main class.
- return self.channel.id
-
- @discord.utils.cached_property
def guild(self):
"""Returns the guild associated with this context's command. None if not available."""
return self.message.guild
diff --git a/discord/reaction.py b/discord/reaction.py
index d80f716b..9c75bfec 100644
--- a/discord/reaction.py
+++ b/discord/reaction.py
@@ -113,7 +113,7 @@ class Reaction:
A list of users who reacted to the message.
"""
- # TODO: Return an iterator a la `MessageChannel.history`?
+ # TODO: Return an iterator a la `Messageable.history`?
if self.custom_emoji:
emoji = '{0.name}:{0.id}'.format(self.emoji)