aboutsummaryrefslogtreecommitdiff
path: root/discord/abc.py
diff options
context:
space:
mode:
Diffstat (limited to 'discord/abc.py')
-rw-r--r--discord/abc.py277
1 files changed, 277 insertions, 0 deletions
diff --git a/discord/abc.py b/discord/abc.py
index 2bda266e..0b42b0e8 100644
--- a/discord/abc.py
+++ b/discord/abc.py
@@ -25,6 +25,12 @@ DEALINGS IN THE SOFTWARE.
"""
import abc
+import io
+import os
+import asyncio
+
+from .message import Message
+from .iterators import LogsFromIterator
class Snowflake(metaclass=abc.ABCMeta):
__slots__ = ()
@@ -75,3 +81,274 @@ class User(metaclass=abc.ABCMeta):
return NotImplemented
return True
return NotImplemented
+
+class GuildChannel(metaclass=abc.ABCMeta):
+ __slots__ = ()
+
+ @property
+ @abc.abstractmethod
+ def mention(self):
+ raise NotImplementedError
+
+ @abc.abstractmethod
+ def overwrites_for(self, obj):
+ raise NotImplementedError
+
+ @abc.abstractmethod
+ def permissions_for(self, user):
+ raise NotImplementedError
+
+ @classmethod
+ def __subclasshook__(cls, C):
+ if cls is GuildChannel:
+ if Snowflake.__subclasshook__(C) is NotImplemented:
+ return NotImplemented
+
+ mro = C.__mro__
+ for attr in ('name', 'server', 'overwrites_for', 'permissions_for', 'mention'):
+ for base in mro:
+ if attr in base.__dict__:
+ break
+ else:
+ return NotImplemented
+ return True
+ return NotImplemented
+
+class PrivateChannel(metaclass=abc.ABCMeta):
+ __slots__ = ()
+
+ @classmethod
+ def __subclasshook__(cls, C):
+ if cls is PrivateChannel:
+ if Snowflake.__subclasshook__(C) is NotImplemented:
+ return NotImplemented
+
+ mro = C.__mro__
+ for base in mro:
+ if 'me' in base.__dict__:
+ return True
+ return NotImplemented
+ return NotImplemented
+
+class MessageChannel(metaclass=abc.ABCMeta):
+ __slots__ = ()
+
+ @abc.abstractmethod
+ def _get_destination(self):
+ raise NotImplementedError
+
+ @asyncio.coroutine
+ def send_message(self, content, *, tts=False):
+ """|coro|
+
+ Sends a message to the channel with the content given.
+
+ The content must be a type that can convert to a string through ``str(content)``.
+
+ Parameters
+ ------------
+ content
+ The content of the message to send.
+ tts: bool
+ Indicates if the message should be sent using text-to-speech.
+
+ Raises
+ --------
+ HTTPException
+ Sending the message failed.
+ Forbidden
+ You do not have the proper permissions to send the message.
+
+ Returns
+ ---------
+ :class:`Message`
+ The message that was sent.
+ """
+
+ channel_id, guild_id = self._get_destination()
+ content = str(content)
+ data = yield from self._state.http.send_message(channel_id, content, guild_id=guild_id, tts=tts)
+ return Message(channel=self, state=self._state, data=data)
+
+ @asyncio.coroutine
+ def send_typing(self):
+ """|coro|
+
+ Send a *typing* status to the channel.
+
+ *Typing* status 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)
+
+ @asyncio.coroutine
+ def upload(self, fp, *, filename=None, content=None, tts=False):
+ """|coro|
+
+ Sends a message to the channel with the file given.
+
+ The ``fp`` parameter should be either a string denoting the location for a
+ file or a *file-like object*. The *file-like object* passed is **not closed**
+ at the end of execution. You are responsible for closing it yourself.
+
+ .. note::
+
+ If the file-like object passed is opened via ``open`` then the modes
+ 'rb' should be used.
+
+ The ``filename`` parameter is the filename of the file.
+ If this is not given then it defaults to ``fp.name`` or if ``fp`` is a string
+ then the ``filename`` will default to the string given. You can overwrite
+ this value by passing this in.
+
+ Parameters
+ ------------
+ fp
+ The *file-like object* or file path to send.
+ filename: str
+ The filename of the file. Defaults to ``fp.name`` if it's available.
+ content: str
+ The content of the message to send along with the file. This is
+ forced into a string by a ``str(content)`` call.
+ tts: bool
+ If the content of the message should be sent with TTS enabled.
+
+ Raises
+ -------
+ HTTPException
+ Sending the file failed.
+
+ Returns
+ --------
+ :class:`Message`
+ The message sent.
+ """
+
+ channel_id, guild_id = self._get_destination()
+
+ try:
+ with open(fp, 'rb') as f:
+ buffer = io.BytesIO(f.read())
+ if filename is None:
+ _, filename = os.path.split(fp)
+ except TypeError:
+ buffer = fp
+
+ state = self._state
+ data = yield from state.http.send_file(channel_id, buffer, guild_id=guild_id,
+ filename=filename, content=content, tts=tts)
+
+ return Message(channel=self, state=state, data=data)
+
+ @asyncio.coroutine
+ def get_message(self, id):
+ """|coro|
+
+ Retrieves a single :class:`Message` from a channel.
+
+ This can only be used by bot accounts.
+
+ Parameters
+ ------------
+ id: int
+ The message ID to look for.
+
+ Returns
+ --------
+ :class:`Message`
+ The message asked for.
+
+ Raises
+ --------
+ NotFound
+ The specified message was not found.
+ Forbidden
+ You do not have the permissions required to get a message.
+ HTTPException
+ Retrieving the message failed.
+ """
+
+ data = yield from self._state.http.get_message(self.id, id)
+ return Message(channel=self, state=self._state, data=data)
+
+ @asyncio.coroutine
+ def pins(self):
+ """|coro|
+
+ Returns a list of :class:`Message` that are currently pinned.
+
+ Raises
+ -------
+ HTTPException
+ Retrieving the pinned messages failed.
+ """
+
+ state = self._state
+ data = yield from state.http.pins_from(self.id)
+ return [Message(channel=self, 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.
+
+ You must have Read Message History permissions to use this.
+
+ All parameters are optional.
+
+ Parameters
+ -----------
+ limit: int
+ The number of messages to retrieve.
+ before: :class:`Message` or `datetime`
+ Retrieve messages before this date or message.
+ If a date is provided it must be a timezone-naive datetime representing UTC time.
+ after: :class:`Message` or `datetime`
+ Retrieve messages after this date or message.
+ If a date is provided it must be a timezone-naive datetime representing UTC time.
+ around: :class:`Message` or `datetime`
+ Retrieve messages around this date or message.
+ If a date is provided it must be a timezone-naive datetime representing UTC time.
+ When using this argument, the maximum limit is 101. Note that if the limit is an
+ even number then this will return at most limit + 1 messages.
+ reverse: bool
+ If set to true, return messages in oldest->newest order. If unspecified,
+ this defaults to ``False`` for most cases. However if passing in a
+ ``after`` parameter then this is set to ``True``. This avoids getting messages
+ out of order in the ``after`` case.
+
+ Raises
+ ------
+ Forbidden
+ You do not have permissions to get channel message history.
+ HTTPException
+ The request to get message history failed.
+
+ Yields
+ -------
+ :class:`Message`
+ The message with the message data parsed.
+
+ Examples
+ ---------
+
+ Usage ::
+
+ counter = 0
+ async for message in channel.history(limit=200):
+ if message.author == client.user:
+ counter += 1
+
+ Python 3.4 Usage ::
+
+ count = 0
+ iterator = channel.history(limit=200)
+ while True:
+ try:
+ message = yield from iterator.get()
+ except discord.NoMoreMessages:
+ break
+ else:
+ if message.author == client.user:
+ counter += 1
+ """
+ return LogsFromIterator(self, limit=limit, before=before, after=after, around=around, reverse=reverse)