aboutsummaryrefslogtreecommitdiff
path: root/docs
diff options
context:
space:
mode:
authorRapptz <[email protected]>2017-05-12 20:14:34 -0400
committerRapptz <[email protected]>2017-05-12 20:14:34 -0400
commitb44bba6ee6e29b38d1e579c602821582e155ec3b (patch)
tree355df44874b3e5f8ee4e825339cb57783e3677ca /docs
parentRename abc.Callable to abc.Connectable. (diff)
downloaddiscord.py-b44bba6ee6e29b38d1e579c602821582e155ec3b.tar.xz
discord.py-b44bba6ee6e29b38d1e579c602821582e155ec3b.zip
First pass at documentation reform.
Diffstat (limited to 'docs')
-rw-r--r--docs/_static/style.css40
-rw-r--r--docs/api.rst413
-rw-r--r--docs/conf.py10
-rw-r--r--docs/discord.rst92
-rw-r--r--docs/ext/commands/api.rst197
-rw-r--r--docs/ext/commands/index.rst13
-rw-r--r--docs/faq.rst174
-rw-r--r--docs/images/discord_client_id.pngbin0 -> 5648 bytes
-rw-r--r--docs/images/discord_create_bot_user_button.pngbin0 -> 32460 bytes
-rw-r--r--docs/images/discord_finished_bot_user.pngbin0 -> 25998 bytes
-rw-r--r--docs/images/discord_new_app_button.PNGbin0 -> 3864 bytes
-rw-r--r--docs/images/discord_new_app_form.pngbin0 -> 34500 bytes
-rw-r--r--docs/images/discord_reveal_token.pngbin0 -> 5784 bytes
-rw-r--r--docs/images/snake.pngbin0 -> 28244 bytes
-rw-r--r--docs/index.rst48
-rw-r--r--docs/intro.rst112
-rw-r--r--docs/migrating.rst1113
-rw-r--r--docs/migrating_to_async.rst322
-rw-r--r--docs/quickstart.rst76
-rw-r--r--docs/whats_new.rst16
20 files changed, 2156 insertions, 470 deletions
diff --git a/docs/_static/style.css b/docs/_static/style.css
new file mode 100644
index 00000000..12c1fd6d
--- /dev/null
+++ b/docs/_static/style.css
@@ -0,0 +1,40 @@
+body {
+ font-family: Georgia, 'Hiragino Mincho Pro', serif;
+ font-size: 16px;
+}
+
+pre, code {
+ font-family: 'Consolas', 'Menlo', 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace;
+ font-size: 0.9em;
+}
+
+code.descname, code.descclassname {
+ font-size: 0.95em;
+}
+
+code.descname {
+ background-color: transparent;
+ font-weight: bold;
+}
+
+pre, * pre {
+ padding: 7px 0 7px 30px !important;
+ margin: 15px 0 !important;
+ line-height: 1.3;
+}
+
+div.warning {
+ background-color: #ffe6cc;
+ border: 1px solid #ffd5aa;
+}
+
+/* don't link-ify the FAQ page */
+a.toc-backref {
+ text-decoration: none;
+ color: #3E4349;
+}
+
+code.xref {
+ background-color: #ecf0f3;
+ border-bottom: 1px dotted #222;
+}
diff --git a/docs/api.rst b/docs/api.rst
index 16ad04ef..55dbaa5f 100644
--- a/docs/api.rst
+++ b/docs/api.rst
@@ -79,21 +79,22 @@ overriding the specific events. For example: ::
import discord
class MyClient(discord.Client):
+ async def on_message(self, message):
+ if message.author != self.user:
+ return
- @asyncio.coroutine
- def on_message(self, message):
- yield from self.send_message(message.channel, 'Hello World!')
+ if message.content.startswith('$hello'):
+ await message.channel.send('Hello World!')
If an event handler raises an exception, :func:`on_error` will be called
-to handle it, which defaults to print a traceback and ignore the exception.
+to handle it, which defaults to print a traceback and ignoring the exception.
.. warning::
All the events must be a |corourl|_. If they aren't, then you might get unexpected
- errors. In order to turn a function into a coroutine they must either be decorated
- with ``@asyncio.coroutine`` or in Python 3.5+ be defined using the ``async def``
- declaration.
+ errors. In order to turn a function into a coroutine they must either be ``async def``
+ functions or in 3.4 decorated with ``@asyncio.coroutine``.
The following two functions are examples of coroutine functions: ::
@@ -104,14 +105,6 @@ to handle it, which defaults to print a traceback and ignore the exception.
def on_ready():
pass
- Since this can be a potentially common mistake, there is a helper
- decorator, :meth:`Client.async_event` to convert a basic function
- into a coroutine and an event at the same time. Note that it is
- not necessary if you use ``async def``.
-
-.. versionadded:: 0.7.0
- Subclassing to listen to events.
-
.. function:: on_connect()
Called when the client has successfully connected to Discord. This is not
@@ -164,48 +157,71 @@ to handle it, which defaults to print a traceback and ignore the exception.
:param kwargs: The keyword arguments for the event that raised the
execption.
-.. function:: on_message(message)
-
- Called when a message is created and sent to a guild.
-
- :param message: A :class:`Message` of the current message.
-
.. function:: on_socket_raw_receive(msg)
- Called whenever a message is received from the websocket, before
- it's processed.This event is always dispatched when a message is
+ Called whenever a message is received from the WebSocket, before
+ it's processed. This event is always dispatched when a message is
received and the passed data is not processed in any way.
- This is only really useful for grabbing the websocket stream and
+ This is only really useful for grabbing the WebSocket stream and
debugging purposes.
.. note::
This is only for the messages received from the client
- websocket. The voice websocket will not trigger this event.
+ WebSocket. The voice WebSocket will not trigger this event.
- :param msg: The message passed in from the websocket library.
+ :param msg: The message passed in from the WebSocket library.
Could be ``bytes`` for a binary message or ``str``
for a regular message.
.. function:: on_socket_raw_send(payload)
- Called whenever a send operation is done on the websocket before the
- message is sent. The passed parameter is the message that is to
- sent to the websocket.
+ Called whenever a send operation is done on the WebSocket before the
+ message is sent. The passed parameter is the message that is being
+ sent to the WebSocket.
- This is only really useful for grabbing the websocket stream and
+ This is only really useful for grabbing the WebSocket stream and
debugging purposes.
.. note::
This is only for the messages received from the client
- websocket. The voice websocket will not trigger this event.
+ WebSocket. The voice WebSocket will not trigger this event.
:param payload: The message that is about to be passed on to the
- websocket library. It can be ``bytes`` to denote a binary
+ WebSocket library. It can be ``bytes`` to denote a binary
message or ``str`` to denote a regular text message.
+.. function:: on_typing(channel, user, when)
+
+ Called when someone begins typing a message.
+
+ The ``channel`` parameter can be a :class:`abc.Messageable` instance.
+ Which could either be :class:`TextChannel`, :class:`GroupChannel`, or
+ :class:`DMChannel`.
+
+ If the ``channel`` is a :class:`TextChannel` then the ``user`` parameter
+ is a :class:`Member`, otherwise it is a :class:`User`.
+
+ :param channel: The location where the typing originated from.
+ :param user: The user that started typing.
+ :param when: A ``datetime.datetime`` object representing when typing started.
+
+.. function:: on_message(message)
+
+ Called when a :class:`Message` is created and sent.
+
+ .. warning::
+
+ Your bot's own messages and private messages are sent through this
+ event. This can lead cases of 'recursion' depending on how your bot was
+ programmed. If you want the bot to not reply to itself, consider
+ checking the user IDs. Note that :class:`~ext.commands.Bot` does not
+ have this problem.
+
+ :param message: A :class:`Message` of the current message.
+
.. function:: on_message_delete(message)
Called when a message is deleted. If the message is not found in the
@@ -218,7 +234,7 @@ to handle it, which defaults to print a traceback and ignore the exception.
.. function:: on_message_edit(before, after)
- Called when a message receives an update event. If the message is not found
+ Called when a :class:`Message` receives an update event. If the message is not found
in the :attr:`Client.messages` cache, then these events will not be called.
This happens if the message is too old or the client is participating in high
traffic guilds. To fix this, increase the ``max_messages`` option of :class:`Client`.
@@ -228,7 +244,9 @@ to handle it, which defaults to print a traceback and ignore the exception.
- A message has been pinned or unpinned.
- The message content has been changed.
- The message has received an embed.
- - For performance reasons, the embed guild does not do this in a "consistent" manner.
+
+ - For performance reasons, the embed server does not do this in a "consistent" manner.
+
- A call message has received an update to its participants or ending time.
:param before: A :class:`Message` of the previous version of the message.
@@ -242,7 +260,7 @@ to handle it, which defaults to print a traceback and ignore the exception.
.. note::
- To get the message being reacted, access it via :attr:`Reaction.message`.
+ To get the :class:`Message` being reacted, access it via :attr:`Reaction.message`.
:param reaction: A :class:`Reaction` showing the current state of the reaction.
:param user: A :class:`User` or :class:`Member` of the user who added the reaction.
@@ -269,31 +287,51 @@ to handle it, which defaults to print a traceback and ignore the exception.
:param message: The :class:`Message` that had its reactions cleared.
:param reactions: A list of :class:`Reaction`\s that were removed.
-.. function:: on_channel_delete(channel)
- on_channel_create(channel)
+.. function:: on_private_channel_delete(channel)
+ on_private_channel_create(channel)
- Called whenever a channel is removed or added from a guild.
+ Called whenever a private channel is deleted or created.
- Note that you can get the guild from :attr:`Channel.guild`.
- :func:`on_channel_create` could also pass in a :class:`PrivateChannel` depending
- on the value of :attr:`Channel.is_private`.
+ :param channel: The :class:`abc.PrivateChannel` that got created or deleted.
- :param channel: The :class:`Channel` that got added or deleted.
+.. function:: on_private_channel_update(before, after)
+
+ Called whenever a private group DM is updated. e.g. changed name or topic.
+
+ :param before: The :class:`GroupChannel` that got updated with the old info.
+ :param after: The :class:`GroupChannel` that got updated with the updated info.
+
+.. function:: on_private_channel_pins_update(channel, last_pin)
+
+ Called whenever a message is pinned or unpinned from a private channel.
+
+ :param channel: The :class:`abc.PrivateChannel` that had it's pins updated.
+ :param last_pin: A ``datetime.datetime`` object representing when the latest message
+ was pinned or ``None`` if there are no pins.
-.. function:: on_channel_update(before, after)
+.. function:: on_guild_channel_delete(channel)
+ on_guild_channel_create(channel)
- Called whenever a channel is updated. e.g. changed name, topic, permissions.
+ Called whenever a guild channel is deleted or created.
- :param before: The :class:`Channel` that got updated with the old info.
- :param after: The :class:`Channel` that got updated with the updated info.
+ Note that you can get the guild from :attr:`~abc.GuildChannel.guild`.
-.. function:: on_channel_pins_update(channel, last_pin)
+ :param channel: The :class:`abc.GuildChannel` that got created or deleted.
- Called whenever a message is pinned or unpinned from a channel.
+.. function:: on_guild_channel_update(before, after)
- :param channel: The :class:`Channel` that had it's pins updated.
+ Called whenever a guild channel is updated. e.g. changed name, topic, permissions.
+
+ :param before: The :class:`abc.GuildChannel` that got updated with the old info.
+ :param after: The :class:`abc.GuildChannel` that got updated with the updated info.
+
+.. function:: on_guild_channel_pins_update(channel, last_pin)
+
+ Called whenever a message is pinned or unpinned from a guild channel.
+
+ :param channel: The :class:`abc.GuildChannel` that had it's pins updated.
:param last_pin: A ``datetime.datetime`` object representing when the latest message
- was pinned or ``None`` if there are no pins.
+ was pinned or ``None`` if there are no pins.
.. function:: on_member_join(member)
on_member_remove(member)
@@ -368,10 +406,11 @@ to handle it, which defaults to print a traceback and ignore the exception.
:param before: The :class:`Role` that updated with the old info.
:param after: The :class:`Role` that updated with the updated info.
-.. function:: on_guild_emojis_update(before, after)
+.. function:: on_guild_emojis_update(guild, before, after)
Called when a :class:`Guild` adds or removes :class:`Emoji`.
+ :param guild: The :class:`Guild` who got their emojis updated.
:param before: A list of :class:`Emoji` before the update.
:param after: A list of :class:`Emoji` after the update.
@@ -383,9 +422,9 @@ to handle it, which defaults to print a traceback and ignore the exception.
:param guild: The :class:`Guild` that has changed availability.
-.. function:: on_voice_state_update(before, after)
+.. function:: on_voice_state_update(member, before, after)
- Called when a :class:`Member` changes their voice state.
+ Called when a :class:`Member` changes their :class:`VoiceState`.
The following, but not limited to, examples illustrate when this event is called:
@@ -394,35 +433,25 @@ to handle it, which defaults to print a traceback and ignore the exception.
- A member is muted or deafened by their own accord.
- A member is muted or deafened by a guild administrator.
- :param before: The :class:`Member` whose voice state changed prior to the changes.
- :param after: The :class:`Member` whose voice state changed after the changes.
-
-.. function:: on_member_ban(member)
+ :param member: The :class:`Member` whose voice states changed.
+ :param before: The :class:`VoiceState` prior to the changes.
+ :param after: The :class:`VoiceState` after to the changes.
- Called when a :class:`Member` gets banned from a :class:`Guild`.
+.. function:: on_member_ban(guild, user)
- You can access the guild that the member got banned from via :attr:`Member.guild`.
+ Called when user gets banned from a :class:`Guild`.
- :param member: The member that got banned.
+ :param guild: The :class:`Guild` the user got banned from.
+ :param user: The user that got banned.
+ Can be either :class:`User` or :class:`Member` depending if
+ the user was in the guild or not at the time of removal.
.. function:: on_member_unban(guild, user)
Called when a :class:`User` gets unbanned from a :class:`Guild`.
- :param guild: The guild the user got unbanned from.
- :param user: The user that got unbanned.
-
-.. function:: on_typing(channel, user, when)
-
- Called when someone begins typing a message.
-
- The ``channel`` parameter could either be a :class:`PrivateChannel` or a
- :class:`Channel`. If ``channel`` is a :class:`PrivateChannel` then the
- ``user`` parameter is a :class:`User`, otherwise it is a :class:`Member`.
-
- :param channel: The location where the typing originated from.
- :param user: The user that started typing.
- :param when: A ``datetime.datetime`` object representing when typing started.
+ :param guild: The :class:`Guild` the user got unbanned from.
+ :param user: The :class:`User` that got unbanned.
.. function:: on_group_join(channel, user)
on_group_remove(channel, user)
@@ -1281,15 +1310,15 @@ this goal, it must make use of a couple of data classes that aid in this goal.
.. attribute:: owner
- *Union[:class:`Member`, :class:`User`]`* – The guild's owner. See also :attr:`Guild.owner`
+ Union[:class:`Member`, :class:`User`] – The guild's owner. See also :attr:`Guild.owner`
.. attribute:: region
- *:class:`GuildRegion`* – The guild's voice region. See also :attr:`Guild.region`.
+ :class:`GuildRegion` – The guild's voice region. See also :attr:`Guild.region`.
.. attribute:: afk_channel
- *Union[:class:`VoiceChannel`, :class:`Object`]* – The guild's AFK channel.
+ Union[:class:`VoiceChannel`, :class:`Object`] – The guild's AFK channel.
If this could not be found, then it falls back to a :class:`Object`
with the ID being set.
@@ -1310,20 +1339,20 @@ this goal, it must make use of a couple of data classes that aid in this goal.
.. attribute:: widget_channel
- *Union[:class:`TextChannel`, :class:`Object`]* – The widget's channel.
+ Union[:class:`TextChannel`, :class:`Object`] – The widget's channel.
If this could not be found then it falls back to a :class:`Object`
with the ID being set.
.. attribute:: verification_level
- *:class:`VerificationLevel`* – The guild's verification level.
+ :class:`VerificationLevel` – The guild's verification level.
See also :attr:`Guild.verification_level`.
.. attribute:: explicit_content_filter
- *:class:`ContentFilter`* – The guild's content filter.
+ :class:`ContentFilter` – The guild's content filter.
See also :attr:`Guild.explicit_content_filter`.
@@ -1365,7 +1394,7 @@ this goal, it must make use of a couple of data classes that aid in this goal.
.. attribute:: overwrites
- *List[Tuple[target, :class:`PermissionOverwrite`]]* – A list of
+ List[Tuple[target, :class:`PermissionOverwrite`]] – A list of
permission overwrite tuples that represents a target and a
:class:`PermissionOverwrite` for said target.
@@ -1377,7 +1406,7 @@ this goal, it must make use of a couple of data classes that aid in this goal.
.. attribute:: roles
- *List[Union[:class:`Role`, :class:`Object`]]* – A list of roles being added or removed
+ List[Union[:class:`Role`, :class:`Object`]] – A list of roles being added or removed
from a member.
If a role is not found then it is a :class:`Object` with the ID and name being
@@ -1403,14 +1432,14 @@ this goal, it must make use of a couple of data classes that aid in this goal.
.. attribute:: permissions
- *:class:`Permissions`* – The permissions of a role.
+ :class:`Permissions` – The permissions of a role.
See also :attr:`Role.permissions`.
.. attribute:: colour
color
- *:class:`Colour`* – The colour of a role.
+ :class:`Colour` – The colour of a role.
See also :attr:`Role.colour`
@@ -1434,14 +1463,14 @@ this goal, it must make use of a couple of data classes that aid in this goal.
.. attribute:: channel
- *Union[:class:`abc.GuildChannel`, :class:`Object`]* – A guild channel.
+ Union[:class:`abc.GuildChannel`, :class:`Object`] – A guild channel.
If the channel is not found then it is a :class:`Object` with the ID
being set. In some cases the channel name is also set.
.. attribute:: inviter
- *:class:`User`* – The user who created the invite.
+ :class:`User` – The user who created the invite.
See also :attr:`Invite.inviter`.
@@ -1472,7 +1501,7 @@ this goal, it must make use of a couple of data classes that aid in this goal.
.. attribute:: allow
deny
- *:class:`Permissions`* – The permissions being allowed or denied.
+ :class:`Permissions` – The permissions being allowed or denied.
.. attribute:: id
@@ -1487,43 +1516,72 @@ this goal, it must make use of a couple of data classes that aid in this goal.
.. this is currently missing the following keys: reason and application_id
I'm not sure how to about porting these
-.. _discord_api_data:
+.. _discord_api_abcs:
-Data Classes
---------------
+Abstract Base Classes
+-----------------------
-Some classes are just there to be data containers, this lists them.
+An abstract base class (also known as an ``abc``) is a class that models can inherit
+to get their behaviour. The Python implementation of an `abc <https://docs.python.org/3/library/abc.html>`_ is
+slightly different in that you can register them at run-time. **Abstract base classes cannot be instantiated**.
+They are mainly there for usage with ``isinstance`` and ``issubclass``\.
-.. note::
+This library has a module related to abstract base classes, some of which are actually from the ``abc`` standard
+module, others which are not.
+
+.. autoclass:: discord.abc.Snowflake
+ :members:
+
+.. autoclass:: discord.abc.User
+ :members:
- With the exception of :class:`Object`, :class:`Colour`, and :class:`Permissions` the
- data classes listed below are **not intended to be created by users** and are also
+.. autoclass:: discord.abc.PrivateChannel
+ :members:
+
+.. autoclass:: discord.abc.GuildChannel
+ :members:
+
+.. autoclass:: discord.abc.Messageable
+ :members:
+ :exclude-members: history typing
+
+ .. autocomethod:: discord.abc.Messageable.history
+ :async-for:
+
+ .. autocomethod:: discord.abc.Messageable.typing
+ :async-with:
+
+.. autoclass:: discord.abc.Connectable
+
+.. _discord_api_models:
+
+Discord Models
+---------------
+
+Models are classes that are received from Discord and are not meant to be created by
+the user of the library.
+
+.. danger::
+
+ The classes listed below are **not intended to be created by users** and are also
**read-only**.
For example, this means that you should not make your own :class:`User` instances
nor should you modify the :class:`User` instance yourself.
- If you want to get one of these data classes instances they'd have to be through
+ If you want to get one of these model classes instances they'd have to be through
the cache, and a common way of doing so is through the :func:`utils.find` function
- or attributes of data classes that you receive from the events specified in the
+ or attributes of model classes that you receive from the events specified in the
:ref:`discord-api-events`.
+.. note::
-.. warning::
-
- Nearly all data classes here have ``__slots__`` defined which means that it is
- impossible to have dynamic attributes to the data classes. The only exception
- to this rule is :class:`Object` which was designed with dynamic attributes in
- mind.
+ Nearly all classes here have ``__slots__`` defined which means that it is
+ impossible to have dynamic attributes to the data classes.
More information about ``__slots__`` can be found
`in the official python documentation <https://docs.python.org/3/reference/datamodel.html#slots>`_.
-Object
-~~~~~~~
-
-.. autoclass:: Object
- :members:
ClientUser
~~~~~~~~~~~~
@@ -1544,6 +1602,13 @@ User
.. autoclass:: User
:members:
:inherited-members:
+ :exclude-members: history typing
+
+ .. autocomethod:: history
+ :async-for:
+
+ .. autocomethod:: typing
+ :async-with:
Message
~~~~~~~
@@ -1556,18 +1621,10 @@ Reaction
.. autoclass:: Reaction
:members:
+ :exclude-members: users
-Embed
-~~~~~~
-
-.. autoclass:: Embed
- :members:
-
-File
-~~~~~
-
-.. autoclass:: File
- :members:
+ .. autocomethod:: users
+ :async-for:
CallMessage
~~~~~~~~~~~~
@@ -1586,6 +1643,10 @@ Guild
.. autoclass:: Guild
:members:
+ :exclude-members: audit_logs
+
+ .. autocomethod:: audit_logs
+ :async-for:
Member
~~~~~~
@@ -1593,6 +1654,13 @@ Member
.. autoclass:: Member
:members:
:inherited-members:
+ :exclude-members: history typing
+
+ .. autocomethod:: history
+ :async-for:
+
+ .. autocomethod:: typing
+ :async-with:
VoiceState
~~~~~~~~~~~
@@ -1600,18 +1668,6 @@ VoiceState
.. autoclass:: VoiceState
:members:
-Colour
-~~~~~~
-
-.. autoclass:: Colour
- :members:
-
-Game
-~~~~
-
-.. autoclass:: Game
- :members:
-
Emoji
~~~~~
@@ -1624,25 +1680,19 @@ Role
.. autoclass:: Role
:members:
-Permissions
-~~~~~~~~~~~~
-
-.. autoclass:: Permissions
- :members:
-
-PermissionOverwrite
-~~~~~~~~~~~~~~~~~~~~
-
-.. autoclass:: PermissionOverwrite
- :members:
-
-
TextChannel
~~~~~~~~~~~~
.. autoclass:: TextChannel
:members:
:inherited-members:
+ :exclude-members: history typing
+
+ .. autocomethod:: history
+ :async-for:
+
+ .. autocomethod:: typing
+ :async-with:
VoiceChannel
~~~~~~~~~~~~~
@@ -1657,6 +1707,13 @@ DMChannel
.. autoclass:: DMChannel
:members:
:inherited-members:
+ :exclude-members: history typing
+
+ .. autocomethod:: history
+ :async-for:
+
+ .. autocomethod:: typing
+ :async-with:
GroupChannel
~~~~~~~~~~~~
@@ -1664,6 +1721,13 @@ GroupChannel
.. autoclass:: GroupChannel
:members:
:inherited-members:
+ :exclude-members: history typing
+
+ .. autocomethod:: history
+ :async-for:
+
+ .. autocomethod:: typing
+ :async-with:
Invite
@@ -1672,6 +1736,69 @@ Invite
.. autoclass:: Invite
:members:
+.. _discord_api_data:
+
+Data Classes
+--------------
+
+Some classes are just there to be data containers, this lists them.
+
+Unlike :ref:`models <discord_api_models>` you are allowed to create
+these yourself, even if they can also be used to hold attributes.
+
+Nearly all classes here have ``__slots__`` defined which means that it is
+impossible to have dynamic attributes to the data classes.
+
+The only exception to this rule is :class:`Object`, which is made with
+dynamic attributes in mind.
+
+More information about ``__slots__`` can be found
+`in the official python documentation <https://docs.python.org/3/reference/datamodel.html#slots>`_.
+
+
+Object
+~~~~~~~
+
+.. autoclass:: Object
+ :members:
+
+Embed
+~~~~~~
+
+.. autoclass:: Embed
+ :members:
+
+File
+~~~~~
+
+.. autoclass:: File
+ :members:
+
+Colour
+~~~~~~
+
+.. autoclass:: Colour
+ :members:
+
+Game
+~~~~
+
+.. autoclass:: Game
+ :members:
+
+Permissions
+~~~~~~~~~~~~
+
+.. autoclass:: Permissions
+ :members:
+
+PermissionOverwrite
+~~~~~~~~~~~~~~~~~~~~
+
+.. autoclass:: PermissionOverwrite
+ :members:
+
+
Exceptions
------------
diff --git a/docs/conf.py b/docs/conf.py
index f46aadc9..53e6b2b3 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -34,6 +34,7 @@ sys.path.insert(0, os.path.abspath('..'))
extensions = [
'sphinx.ext.autodoc',
'sphinx.ext.extlinks',
+ 'sphinxcontrib.asyncio'
]
if on_rtd:
@@ -115,7 +116,7 @@ exclude_patterns = ['_build']
#show_authors = False
# The name of the Pygments (syntax highlighting) style to use.
-pygments_style = 'sphinx'
+pygments_style = 'friendly'
# A list of ignored prefixes for module index sorting.
#modindex_common_prefix = []
@@ -128,7 +129,7 @@ pygments_style = 'sphinx'
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
-html_theme = 'sphinx_rtd_theme'
+html_theme = 'alabaster'
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
@@ -159,7 +160,7 @@ html_theme = 'sphinx_rtd_theme'
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
-# html_static_path = ['_static']
+html_static_path = ['_static']
# Add any extra paths that contain custom files (such as robots.txt or
# .htaccess) here, relative to this directory. These files are copied
@@ -304,3 +305,6 @@ texinfo_documents = [
# If true, do not generate a @detailmenu in the "Top" node's menu.
#texinfo_no_detailmenu = False
+
+def setup(app):
+ app.add_stylesheet('style.css')
diff --git a/docs/discord.rst b/docs/discord.rst
new file mode 100644
index 00000000..b9a3bad2
--- /dev/null
+++ b/docs/discord.rst
@@ -0,0 +1,92 @@
+.. _discord-intro:
+
+Creating a Bot Account
+========================
+
+In order to work with the library and the Discord API in general, we must first create a Discord Bot account.
+
+Creating a Bot account is a pretty straightforward process.
+
+1. Make sure you're logged on to the `Discord website <https://discordapp.com>`_.
+2. Navigate to the `application page <https://discordapp.com/developers/applications/me>`_
+3. Click on the "New App" button.
+
+ .. image:: /images/discord_new_app_button.png
+ :alt: The new app button.
+
+4. Give the application a name and a description if wanted and click "Create App".
+
+ - You can also put an avatar you want your bot to use, don't worry you can change this later.
+ - **Leave the Redirect URI(s) blank** unless are creating a service.
+
+ .. image:: /images/discord_new_app_form.png
+ :alt: The new application form filled in.
+5. Create a Bot User by clicking on the accompanying button and confirming it.
+
+ .. image:: /images/discord_create_bot_user_button.png
+ :alt: The Create a Bot User button.
+6. Make sure that **Public Bot** is ticked if you want others to invite your bot.
+
+ - You should also make sure that **Require OAuth2 Code Grant** is unchecked unless you
+ are developing a service that needs it. If you're unsure, then **leave it unchecked**.
+
+ .. figure:: /images/discord_finished_bot_user.png
+
+ How the Bot User options should look like for most people.
+
+7. Click to reveal the token.
+
+ - **This is not the Client Secret**
+
+ .. figure:: /images/discord_reveal_token.png
+
+ How the token reveal button looks like.
+
+And that's it. You now have a bot account and you can login with that token.
+
+.. _discord_invite_bot:
+
+Inviting Your Bot
+-------------------
+
+So you've made a Bot User but it's not actually in any server.
+
+If you want to invite your bot you must create an invite URL for your bot.
+
+First, you must fetch the Client ID of the Bot. You can find this in the Bot's application page.
+
+.. image:: /images/discord_client_id.png
+ :alt: The Bot's Client ID.
+
+Copy paste that into the pre-formatted URL:
+
+.. code-block:: none
+
+ https://discordapp.com/oauth2/authorize?client_id=YOUR_CLIENT_ID&scope=bot&permissions=0
+
+Replace ``YOUR_CLIENT_ID`` with the Client ID we got in the previous step. For example,
+in the image above our client ID is 312718641634213889 so the resulting URL would be
+https://discordapp.com/oauth2/authorize?client_id=312718641634213889&scope=bot&permissions=0
+(note that this bot has been deleted).
+
+Now you can click the link and invite your bot to any server you have "Manage Server" permissions on.
+
+Adding Permissions
+~~~~~~~~~~~~~~~~~~~~
+
+In the above URL, you might have noticed an interesting bit, the ``permissions=0`` fragment.
+
+Bot accounts can request specific permissions to be granted upon joining. When the bot joins
+the guild, they will be granted a managed role that contains the permissions you requested.
+If the permissions is 0, then no special role is created.
+
+This ``permissions`` value is calculated based on bit-wise arithmetic. Thankfully, people have
+created a calculate that makes it easy to calculate the permissions necessary visually.
+
+- https://discordapi.com/permissions.html
+- https://finitereality.github.io/permissions/
+
+Feel free to use whichever is easier for you to grasp.
+
+If you want to generate this URL dynamically at run-time inside your bot and using the
+:class:`discord.Permissions` interface, you can use :func:`discord.utils.oauth_url`.
diff --git a/docs/ext/commands/api.rst b/docs/ext/commands/api.rst
new file mode 100644
index 00000000..665a2f33
--- /dev/null
+++ b/docs/ext/commands/api.rst
@@ -0,0 +1,197 @@
+.. currentmodule:: discord
+
+API Reference
+===============
+
+The following section outlines the API of discord.py's command extension module.
+
+Bot
+----
+
+.. autoclass:: discord.ext.commands.Bot
+ :members:
+ :inherited-members:
+
+.. autoclass:: discord.ext.commands.AutoShardedBot
+ :members:
+
+Event Reference
+-----------------
+
+These events function similar to :ref:`the regular events <discord-api-events>`, except they
+are custom to the command extension module.
+
+.. function:: on_command_error(ctx, error)
+
+ An error handler that is called when an error is raised
+ inside a command either through user input error, check
+ failure, or an error in your own code.
+
+ A default one is provided (:meth:`.Bot.on_command_error`).
+
+ :param ctx: The invocation context.
+ :type ctx: :class:`Context`
+ :param error: The error that was raised.
+ :type error: :class:`CommandError` derived
+
+.. function:: on_command(ctx)
+
+ An event that is called when a command is found and is about to be invoked.
+
+ This event is called regardless of whether the command itself succeeds via
+ error or completes.
+
+ :param ctx: The invocation context.
+ :type ctx: :class:`Context`
+
+.. function:: on_command_completion(ctx)
+
+ An event that is called when a command has completed its invocation.
+
+ This event is called only if the command succeeded, i.e. all checks have
+ passed and the user input it correctly.
+
+ :param ctx: The invocation context.
+ :type ctx: :class:`Context`
+
+
+Command
+--------
+
+.. autofunction:: discord.ext.commands.command
+
+.. autofunction:: discord.ext.commands.group
+
+.. autoclass:: discord.ext.commands.Command
+ :members:
+
+.. autoclass:: discord.ext.commands.Group
+ :members:
+ :inherited-members:
+
+.. autoclass:: discord.ext.commands.GroupMixin
+ :members:
+
+
+Formatters
+-----------
+
+.. autoclass:: discord.ext.commands.Paginator
+ :members:
+
+.. autoclass:: discord.ext.commands.HelpFormatter
+ :members:
+
+Checks
+-------
+
+.. autofunction:: discord.ext.commands.check
+
+.. autofunction:: discord.ext.commands.has_role
+
+.. autofunction:: discord.ext.commands.has_permissions
+
+.. autofunction:: discord.ext.commands.has_any_role
+
+.. autofunction:: discord.ext.commands.bot_has_role
+
+.. autofunction:: discord.ext.commands.bot_has_permissions
+
+.. autofunction:: discord.ext.commands.bot_has_any_role
+
+.. autofunction:: discord.ext.commands.cooldown
+
+.. autofunction:: discord.ext.commands.guild_only
+
+.. autofunction:: discord.ext.commands.is_owner
+
+.. autofunction:: discord.ext.commands.is_nsfw
+
+Context
+--------
+
+.. autoclass:: discord.ext.commands.Context
+ :members:
+ :exclude-members: history typing
+
+ .. autocomethod:: discord.ext.commands.Context.history
+ :async-for:
+
+ .. autocomethod:: discord.ext.commands.Context.typing
+ :async-with:
+
+Converters
+------------
+
+.. autoclass:: discord.ext.commands.Converter
+ :members:
+
+.. autoclass:: discord.ext.commands.MemberConverter
+ :members:
+
+.. autoclass:: discord.ext.commands.UserConverter
+ :members:
+
+.. autoclass:: discord.ext.commands.TextChannelConverter
+ :members:
+
+.. autoclass:: discord.ext.commands.InviteConverter
+ :members:
+
+.. autoclass:: discord.ext.commands.RoleConverter
+ :members:
+
+.. autoclass:: discord.ext.commands.GameConverter
+ :members:
+
+.. autoclass:: discord.ext.commands.ColourConverter
+ :members:
+
+.. autoclass:: discord.ext.commands.VoiceChannelConverter
+ :members:
+
+.. autoclass:: discord.ext.commands.EmojiConverter
+ :members:
+
+.. autoclass:: discord.ext.commands.clean_content
+ :members:
+
+Errors
+-------
+
+.. autoexception:: discord.ext.commands.CommandError
+ :members:
+
+.. autoexception:: discord.ext.commands.MissingRequiredArgument
+ :members:
+
+.. autoexception:: discord.ext.commands.BadArgument
+ :members:
+
+.. autoexception:: discord.ext.commands.NoPrivateMessage
+ :members:
+
+.. autoexception:: discord.ext.commands.CheckFailure
+ :members:
+
+.. autoexception:: discord.ext.commands.CommandNotFound
+ :members:
+
+.. autoexception:: discord.ext.commands.DisabledCommand
+ :members:
+
+.. autoexception:: discord.ext.commands.CommandInvokeError
+ :members:
+
+.. autoexception:: discord.ext.commands.TooManyArguments
+ :members:
+
+.. autoexception:: discord.ext.commands.UserInputError
+ :members:
+
+.. autoexception:: discord.ext.commands.CommandOnCooldown
+ :members:
+
+.. autoexception:: discord.ext.commands.NotOwner
+ :members:
+
diff --git a/docs/ext/commands/index.rst b/docs/ext/commands/index.rst
new file mode 100644
index 00000000..908a7bc1
--- /dev/null
+++ b/docs/ext/commands/index.rst
@@ -0,0 +1,13 @@
+``discord.ext.commands`` -- Bot commands framework
+====================================================
+
+``discord.py`` offers a lower level aspect on interacting with Discord. Often times, the library is used for the creation of
+bots. However this task can be daunting and confusing to get correctly the first time. Many times there comes a repetition in
+creating a bot command framework that is extensible, flexible, and powerful. For this reason, ``discord.py`` comes with an
+extension library that handles this for you.
+
+
+.. toctree::
+ :maxdepth: 1
+
+ api
diff --git a/docs/faq.rst b/docs/faq.rst
index 1525b3a6..fda5313b 100644
--- a/docs/faq.rst
+++ b/docs/faq.rst
@@ -16,7 +16,7 @@ Coroutines
Questions regarding coroutines and asyncio belong here.
I get a SyntaxError around the word ``async``\! What should I do?
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This ``SyntaxError`` happens because you're using a Python version lower than 3.5. Python 3.4 uses ``@asyncio.coroutine`` and
``yield from`` instead of ``async def`` and ``await``.
@@ -52,7 +52,7 @@ Where can I use ``await``\?
You can only use ``await`` inside ``async def`` functions and nowhere else.
What does "blocking" mean?
-~~~~~~~~~~~~~~~~~~~~~~~~~~
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
In asynchronous programming a blocking call is essentially all the parts of the function that are not ``await``. Do not
despair however, because not all forms of blocking are bad! Using blocking calls is inevitable, but you must work to make
@@ -78,13 +78,14 @@ Consider the following example: ::
r = requests.get('http://random.cat/meow')
if r.status_code == 200:
js = r.json()
- await client.send_message(channel, js['file'])
+ await channel.send(js['file'])
# good
- async with aiohttp.get('http://random.cat/meow') as r:
- if r.status == 200:
- js = await r.json()
- await client.send_message(channel, js['file'])
+ async with aiohttp.ClientSession() as session:
+ async with session.get('http://random.cat/meow') as r:
+ if r.status == 200:
+ js = await r.json()
+ await channel.send(js['file'])
General
---------
@@ -103,37 +104,41 @@ following: ::
How do I send a message to a specific channel?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-If you have its ID then you can do this in two ways, first is by using :class:`Object`\: ::
+You must fetch the channel directly and then call the appropriate method. Example: ::
- await client.send_message(discord.Object(id='12324234183172'), 'hello')
+ channel = client.get_channel('12324234183172')
+ await channel.send('hello')
-The second way is by calling :meth:`Client.get_channel` directly: ::
+How do I upload an image?
+~~~~~~~~~~~~~~~~~~~~~~~~~~
- await client.send_message(client.get_channel('12324234183172'), 'hello')
+To upload something to Discord you have to use the :class:`File` object.
-I'm passing IDs as integers and things are not working!
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+A :class:`File` accepts two parameters, the file-like object (or file path) and the filename
+to pass to Discord when uploading.
-In the library IDs must be of type ``str`` not of type ``int``. Wrap it in quotes.
+If you want to upload an image it's as simple as: ::
-How do I upload an image?
-~~~~~~~~~~~~~~~~~~~~~~~~~~
+ await channel.send(file=discord.File('my_file.png'))
-There are two ways of doing it. Both of which involve using :meth:`Client.send_file`.
+If you have a file-like object you can do as follows: ::
-The first is by opening the file and passing it directly: ::
+ with open('my_file.png', 'rb') as fp:
+ await channel.send(file=discord.File(fp, 'new_filename.png'))
- with open('my_image.png', 'rb') as f:
- await client.send_file(channel, f)
+To upload multiple files, you can use the ``files`` keyword argument instead of ``file``\: ::
-The second is by passing the file name directly: ::
+ my_files = [
+ discord.File('result.zip'),
+ discord.File('teaser_graph.png'),
+ ]
+ await channel.send(files=my_files)
- await client.send_file(channel, 'my_image.png')
How can I add a reaction to a message?
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-You use the :meth:`Client.add_reaction` method.
+You use the :meth:`Message.add_reaction` method.
If you want to use unicode emoji, you must pass a valid unicode code point in a string. In your code, you can write this in a few different ways:
@@ -141,16 +146,32 @@ If you want to use unicode emoji, you must pass a valid unicode code point in a
- ``'\U0001F44D'``
- ``'\N{THUMBS UP SIGN}'``
-In case you want to use emoji that come from a message, you already get their code points in the content without needing to do anything special.
-You **cannot** send ``':thumbsup:'`` style shorthands.
+Quick example: ::
+
+ await message.add_reaction('\N{THUMBS UP SIGN}')
-For custom emoji, you should pass an instance of :class:`discord.Emoji`. You can also pass a ``'name:id'`` string, but if you can use said emoji,
-you should be able to use :meth:`Client.get_all_emojis`/:attr:`Server.emojis` to find the one you're looking for.
+In case you want to use emoji that come from a message, you already get their code points in the content without needing
+to do anything special. You **cannot** send ``':thumbsup:'`` style shorthands.
+
+For custom emoji, you should pass an instance of :class:`Emoji`. You can also pass a ``'name:id'`` string, but if you
+can use said emoji, you should be able to use :meth:`Client.get_emoji` to get an emoji via ID or use :func:`utils.find`/
+:func:`utils.get` on :attr:`Client.emojis` or :attr:`Guild.emojis` collections.
+
+Quick example: ::
+
+ # if you have the ID already
+ emoji = client.get_emoji(310177266011340803)
+ await message.add_reaction(emoji)
+
+ # no ID, do a lookup
+ emoji = discord.utils.get(guild.emojis, name='LUL')
+ if emoji:
+ await message.add_reaction(emoji)
How do I pass a coroutine to the player's "after" function?
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-A StreamPlayer is just a ``threading.Thread`` object that plays music. As a result it does not execute inside a coroutine.
+The library's music player launches on a separate thread, ergo it does not execute inside a coroutine.
This does not mean that it is not possible to call a coroutine in the ``after`` parameter. To do so you must pass a callable
that wraps up a couple of aspects.
@@ -169,7 +190,7 @@ However, this function returns a ``concurrent.Future`` and to actually call it w
this together we can do the following: ::
def my_after():
- coro = client.send_message(some_channel, 'Song is done!')
+ coro = some_channel.send('Song is done!')
fut = asyncio.run_coroutine_threadsafe(coro, client.loop)
try:
fut.result()
@@ -177,48 +198,44 @@ this together we can do the following: ::
# an error happened sending the message
pass
- player = await voice.create_ytdl_player(url, after=my_after)
- player.start()
-
-Why is my "after" function being called right away?
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-The ``after`` keyword argument expects a *function object* to be passed in. Similar to how ``threading.Thread`` expects a
-callable in its ``target`` keyword argument. This means that the following are invalid:
-
-.. code-block:: python
+ voice.play(discord.FFmpegPCMAudio(url), after=my_after)
- player = await voice.create_ytdl_player(url, after=self.foo())
- other = await voice.create_ytdl_player(url, after=self.bar(10))
+How do I run something in the background?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-However the following are correct:
+`Check the background_task.py example. <https://github.com/Rapptz/discord.py/blob/rewrite/examples/background_task.py>`_
-.. code-block:: python
+How do I get a specific model?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- player = await voice.create_ytdl_player(url, after=self.foo)
- other = await voice.create_ytdl_player(url, after=lambda: self.bar(10))
+There are multiple ways of doing this. If you have a specific model's ID then you can use
+one of the following functions:
-Basically, these functions should not be called.
+- :meth:`Client.get_channel`
+- :meth:`Client.get_guild`
+- :meth:`Client.get_user`
+- :meth:`Client.get_emoji`
+- :meth:`Guild.get_member`
+- :meth:`Guild.get_channel`
+The following use an HTTP request:
-How do I run something in the background?
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+- :meth:`abc.Messageable.get_message`
+- :meth:`Client.get_user_info`
-`Check the background_task.py example. <https://github.com/Rapptz/discord.py/blob/master/examples/background_task.py>`_
-How do I get a specific User/Role/Channel/Server?
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+If the functions above do not help you, then use of :func:`utils.find` or :func:`utils.get` would serve some use in finding
+specific models.
-There are multiple ways of doing this. If you have a specific entity's ID then you can use
-one of the following functions:
+Quick example: ::
-- :meth:`Client.get_channel`
-- :meth:`Client.get_server`
-- :meth:`Server.get_member`
-- :meth:`Server.get_channel`
+ # find a guild by name
+ guild = discord.utils.get(client.guilds, name='My Server')
-If the functions above do not help you, then use of :func:`utils.find` or :func:`utils.get` would serve some use in finding
-specific entities. The documentation for those functions provide specific examples.
+ # make sure to check if it's found
+ if guild is not None:
+ # find a channel by name
+ channel = discord.utils.get(guild.text_channels, name='cool-channel')
Commands Extension
-------------------
@@ -229,10 +246,10 @@ Is there any documentation for this?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Not at the moment. Writing documentation for stuff takes time. A lot of people get by reading the docstrings in the source
-code. Others get by via asking questions in the `Discord server <https://discord.gg/0SBTUU1wZTXZNJPa>`_. Others look at the
+code. Others get by via asking questions in the `Discord server <https://discord.gg/discord-api>`_. Others look at the
source code of `other existing bots <https://github.com/Rapptz/RoboDanny>`_.
-There is a `basic example <https://github.com/Rapptz/discord.py/blob/master/examples/basic_bot.py>`_ showcasing some
+There is a `basic example <https://github.com/Rapptz/discord.py/blob/rewrite/examples/basic_bot.py>`_ showcasing some
functionality.
**Documentation is being worked on, it will just take some time to polish it**.
@@ -249,42 +266,36 @@ Overriding the default provided ``on_message`` forbids any extra commands from r
await bot.process_commands(message)
-Can I use ``bot.say`` in other places aside from commands?
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-No. They only work inside commands due to the way the magic involved works.
-
Why do my arguments require quotes?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In a simple command defined as: ::
@bot.command()
- async def echo(message: str):
- await bot.say(message)
+ async def echo(ctx, message: str):
+ await ctx.send(message)
Calling it via ``?echo a b c`` will only fetch the first argument and disregard the rest. To fix this you should either call
it via ``?echo "a b c"`` or change the signature to have "consume rest" behaviour. Example: ::
@bot.command()
- async def echo(*, message: str):
- await bot.say(message)
+ async def echo(ctx, *, message: str):
+ await ctx.send(message)
This will allow you to use ``?echo a b c`` without needing the quotes.
How do I get the original ``message``\?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Ask the command to pass you the invocation context via ``pass_context``. This context will be passed as the first parameter.
+The :class:`~ext.commands.Context` contains an attribute, :attr:`~ext.commands.Context.message` to get the original
+message.
Example: ::
- @bot.command(pass_context=True)
+ @bot.command()
async def joined_at(ctx, member: discord.Member = None):
- if member is None:
- member = ctx.message.author
-
- await bot.say('{0} joined at {0.joined_at}'.format(member))
+ member = member or ctx.author
+ await ctx.send('{0} joined at {0.joined_at}'.format(member))
How do I make a subcommand?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -294,15 +305,14 @@ the group operating as "subcommands". These groups can be arbitrarily nested as
Example: ::
- @bot.group(pass_context=True)
+ @bot.group()
async def git(ctx):
if ctx.invoked_subcommand is None:
await bot.say('Invalid git command passed...')
@git.command()
- async def push(remote: str, branch: str):
- await bot.say('Pushing to {} {}'.format(remote, branch))
-
+ async def push(ctx, remote: str, branch: str):
+ await ctx.send('Pushing to {} {}'.format(remote, branch))
This could then be used as ``?git push origin master``.
diff --git a/docs/images/discord_client_id.png b/docs/images/discord_client_id.png
new file mode 100644
index 00000000..04710f32
--- /dev/null
+++ b/docs/images/discord_client_id.png
Binary files differ
diff --git a/docs/images/discord_create_bot_user_button.png b/docs/images/discord_create_bot_user_button.png
new file mode 100644
index 00000000..f87940ab
--- /dev/null
+++ b/docs/images/discord_create_bot_user_button.png
Binary files differ
diff --git a/docs/images/discord_finished_bot_user.png b/docs/images/discord_finished_bot_user.png
new file mode 100644
index 00000000..09aff891
--- /dev/null
+++ b/docs/images/discord_finished_bot_user.png
Binary files differ
diff --git a/docs/images/discord_new_app_button.PNG b/docs/images/discord_new_app_button.PNG
new file mode 100644
index 00000000..78a099dd
--- /dev/null
+++ b/docs/images/discord_new_app_button.PNG
Binary files differ
diff --git a/docs/images/discord_new_app_form.png b/docs/images/discord_new_app_form.png
new file mode 100644
index 00000000..68409a6c
--- /dev/null
+++ b/docs/images/discord_new_app_form.png
Binary files differ
diff --git a/docs/images/discord_reveal_token.png b/docs/images/discord_reveal_token.png
new file mode 100644
index 00000000..92d5492a
--- /dev/null
+++ b/docs/images/discord_reveal_token.png
Binary files differ
diff --git a/docs/images/snake.png b/docs/images/snake.png
new file mode 100644
index 00000000..62b44617
--- /dev/null
+++ b/docs/images/snake.png
Binary files differ
diff --git a/docs/index.rst b/docs/index.rst
index 30a41468..883d0146 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -3,23 +3,55 @@
You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive.
-Welcome to discord.py's documentation!
-======================================
+Welcome to the discord.py documentation
+=========================================
-Contents:
+.. image:: /images/snake.png
+
+discord.py is a modern, easy to use, feature-rich, and async ready API wrapper
+for Discord.
+
+**Features:**
+
+- Modern Pythonic API using ``async``\/``await`` syntax
+- Sane rate limit handling that prevents 429s
+- Implements the entirety of the Discord API
+- Command extension to aid with bot creation
+- Easy to use with an object oriented design
+- Optimised for both speed and memory
+
+Documentation Contents
+-----------------------
.. toctree::
:maxdepth: 2
- logging
- whats_new
+ intro
+ quickstart
migrating
+ logging
api
- faq
+Extensions
+-----------
+
+.. toctree::
+ :maxdepth: 2
+
+ ext/commands/index.rst
+
+
+Additional Information
+-----------------------
+
+.. toctree::
+ :maxdepth: 2
+
+ discord
+ faq
+ whats_new
-Indices and tables
-==================
+If you still can't find what you're looking for, try in one of the following pages:
* :ref:`genindex`
* :ref:`modindex`
diff --git a/docs/intro.rst b/docs/intro.rst
new file mode 100644
index 00000000..b3804be1
--- /dev/null
+++ b/docs/intro.rst
@@ -0,0 +1,112 @@
+.. currentmodule:: discord
+
+.. _intro:
+
+Introduction
+==============
+
+This is the documentation for discord.py, a library for Python to aid
+in creating applications that utilise the Discord API.
+
+Prerequisites
+---------------
+
+discord.py works with Python 3.4.2 or higher. Support for earlier versions of Python
+is not provided. Python 2.7 or lower is not supported. Python 3.3 is not supported
+due to one of the dependencies (``aiohttp``) not supporting Python 3.3.
+
+
+.. _installing:
+
+Installing
+-----------
+
+You can get the library directly from PyPI: ::
+
+ python3 -m pip install -U discord.py
+
+If you are using Windows, then the following should be used instead: ::
+
+ py -3 -m pip install -U discord.py
+
+
+To get voice support, you should use ``discord.py[voice]`` instead of ``discord.py``, e.g. ::
+
+ python3 -m pip install -U discord.py[voice]
+
+On Linux environments, installing voice requires getting the following dependencies:
+
+- libffi
+- libnacl
+- python3-dev
+
+For a debian-based system, the following command will help get those dependencies:
+
+.. code-block:: shell
+
+ $ apt install libffi-dev libnacl-dev python3-dev
+
+Remember to check your permissions!
+
+Virtual Environments
+~~~~~~~~~~~~~~~~~~~~~
+
+Sometimes we don't want to pollute our system installs with a library or we want to maintain
+different versions of a library than the currently system installed one. Or we don't have permissions to
+install a library along side with the system installed ones. For this purpose, the standard library as
+of 3.3 comes with a concept called "Virtual Environment" to help maintain these separate versions.
+
+A more in-depth tutorial is found on `the official documentation. <https://docs.python.org/3/tutorial/venv.html>`_
+
+However, for the quick and dirty:
+
+1. Go to your project's working directory:
+
+ .. code-block:: shell
+
+ $ cd your-bot-source
+ $ python3 -m venv bot-env
+
+2. Activate the virtual environment:
+
+ .. code-block:: shell
+
+ $ source bot-env/bin/activate
+
+ On Windows you activate it with:
+
+ .. code-block:: shell
+
+ $ bot-env\Scripts\activate.bat
+
+3. Use pip like usual:
+
+ .. code-block:: shell
+
+ $ pip install -U discord.py
+
+Congratulations. You now have a virtual environment all set up without messing with your system installation.
+
+Basic Concepts
+---------------
+
+discord.py revolves around the concept of :ref:`events <discord-api-events>`.
+An event is something you listen to and then respond to. For example, when a message
+happens, you will receive an event about it and you can then respond to it.
+
+A quick example to showcase how events work:
+
+.. code-block:: python
+
+ import discord
+
+ class MyClient(discord.Client):
+ async def on_ready(self):
+ print('Logged on as {0}!'.format(self.user))
+
+ async def on_message(self, message):
+ print('Message from {0.author}: {0.content}'.format(message))
+
+ client = MyClient()
+ client.run('my token goes here')
+
diff --git a/docs/migrating.rst b/docs/migrating.rst
index 7ad9e6a1..d7365d08 100644
--- a/docs/migrating.rst
+++ b/docs/migrating.rst
@@ -1,336 +1,983 @@
.. currentmodule:: discord
-.. _migrating-to-async:
+.. _migrating_1_0:
-Migrating to v0.10.0
+Migrating to v1.0
======================
-v0.10.0 is one of the biggest breaking changes in the library due to massive
-fundamental changes in how the library operates.
+v1.0 is one of the biggest breaking changes in the library due to a complete
+redesign.
+
+The amount of changes are so massive and long that for all intents and purposes, it is a completely
+new library.
+
+Part of the redesign involves making things more easy to use and natural. Things are done on the
+:ref:`models <discord_api_models>` instead of requiring a :class:`Client` instance to do any work.
+
+Major Model Changes
+---------------------
+
+Below are major model changes that have happened in v1.0
+
+Snowflakes are int
+~~~~~~~~~~~~~~~~~~~~
+
+Before v1.0, all snowflakes (the ``id`` attribute) were strings. This has been changed to ``int``.
+
+Quick example: ::
+
+ # before
+ ch = client.get_channel('84319995256905728')
+ if message.author.id == '80528701850124288':
+ ...
+
+ # after
+ ch = client.get_channel(84319995256905728)
+ if message.author.id == 80528701850124288:
+ ...
+
+This change allows for fewer errors when using the Copy ID feature in the official client since you no longer have
+to wrap it in quotes and allows for optimisation opportunities by allowing ETF to be used instead of JSON internally.
+
+Server is now Guild
+~~~~~~~~~~~~~~~~~~~~~
+
+The official API documentation calls the "Server" concept a "Guild" instead. In order to be more consistent with the
+API documentation when necessary, the model has been renamed to :class:`Guild` and all instances referring to it has
+been changed as well.
+
+A list of changes is as follows:
+
++-------------------------------+----------------------------------+
+| Before | After |
++-------------------------------+----------------------------------+
+| ``Message.server`` | :attr:`Message.guild` |
++-------------------------------+----------------------------------+
+| ``Channel.server`` | :attr:`abc.GuildChannel.guild` |
++-------------------------------+----------------------------------+
+| ``Client.servers`` | :attr:`Client.guilds` |
++-------------------------------+----------------------------------+
+| ``Client.get_server`` | :meth:`Client.get_guild` |
++-------------------------------+----------------------------------+
+| ``Emoji.server`` | :attr:`Emoji.guild` |
++-------------------------------+----------------------------------+
+| ``Role.server`` | :attr:`Role.guild` |
++-------------------------------+----------------------------------+
+| ``Invite.server`` | :attr:`Invite.guild` |
++-------------------------------+----------------------------------+
+| ``Member.server`` | :attr:`Member.guild` |
++-------------------------------+----------------------------------+
+| ``Permissions.manage_server`` | :attr:`Permissions.manage_guild` |
++-------------------------------+----------------------------------+
+| ``VoiceClient.server`` | :attr:`VoiceClient.guild` |
++-------------------------------+----------------------------------+
+| ``Client.create_server`` | :meth:`Client.create_guild` |
++-------------------------------+----------------------------------+
+
+.. _migrating_1_0_model_state:
+
+Models are Stateful
+~~~~~~~~~~~~~~~~~~~~~
+
+As mentioned earlier, a lot of functionality was moved out of :class:`Client` and
+put into their respective :ref:`model <discord_api_models>`.
+
+A list of these changes is enumerated below.
+
++---------------------------------------+------------------------------------------------------------------------------+
+| Before | After |
++---------------------------------------+------------------------------------------------------------------------------+
+| ``Client.add_reaction`` | :meth:`Message.add_reaction` |
++---------------------------------------+------------------------------------------------------------------------------+
+| ``Client.add_roles`` | :meth:`Member.add_roles` |
++---------------------------------------+------------------------------------------------------------------------------+
+| ``Client.ban`` | :meth:`Member.ban` or :meth:`Guild.ban` |
++---------------------------------------+------------------------------------------------------------------------------+
+| ``Client.change_nickname`` | :meth:`Member.edit` |
++---------------------------------------+------------------------------------------------------------------------------+
+| ``Client.clear_reactions`` | :meth:`Message.clear_reactions` |
++---------------------------------------+------------------------------------------------------------------------------+
+| ``Client.create_channel`` | :meth:`Guild.create_text_channel` and :meth:`Guild.create_voice_channel` |
++---------------------------------------+------------------------------------------------------------------------------+
+| ``Client.create_custom_emoji`` | :meth:`Guild.create_custom_emoji` |
++---------------------------------------+------------------------------------------------------------------------------+
+| ``Client.create_invite`` | :meth:`Guild.create_invite` or :meth:`abc.GuildChannel.create_invite` |
++---------------------------------------+------------------------------------------------------------------------------+
+| ``Client.create_role`` | :meth:`Guild.create_role` |
++---------------------------------------+------------------------------------------------------------------------------+
+| ``Client.delete_channel`` | :meth:`abc.GuildChannel.delete` |
++---------------------------------------+------------------------------------------------------------------------------+
+| ``Client.delete_channel_permissions`` | :meth:`abc.GuildChannel.set_permissions` with ``overwrites`` set to ``None`` |
++---------------------------------------+------------------------------------------------------------------------------+
+| ``Client.delete_custom_emoji`` | :meth:`Emoji.delete` |
++---------------------------------------+------------------------------------------------------------------------------+
+| ``Client.delete_invite`` | :meth:`Invite.delete` or :meth:`Client.delete_invite` |
++---------------------------------------+------------------------------------------------------------------------------+
+| ``Client.delete_message`` | :meth:`Message.delete` |
++---------------------------------------+------------------------------------------------------------------------------+
+| ``Client.delete_messages`` | :meth:`TextChannel.delete_messages` |
++---------------------------------------+------------------------------------------------------------------------------+
+| ``Client.delete_role`` | :meth:`Role.delete` |
++---------------------------------------+------------------------------------------------------------------------------+
+| ``Client.delete_server`` | :meth:`Guild.delete` |
++---------------------------------------+------------------------------------------------------------------------------+
+| ``Client.edit_channel`` | :meth:`TextChannel.edit` or :meth:`VoiceChannel.edit` |
++---------------------------------------+------------------------------------------------------------------------------+
+| ``Client.edit_channel_permissions`` | :meth:`abc.GuildChannel.set_permissions` |
++---------------------------------------+------------------------------------------------------------------------------+
+| ``Client.edit_custom_emoji`` | :meth:`Emoji.edit` |
++---------------------------------------+------------------------------------------------------------------------------+
+| ``Client.edit_message`` | :meth:`Message.edit` |
++---------------------------------------+------------------------------------------------------------------------------+
+| ``Client.edit_profile`` | :meth:`ClientUser.edit` (you get this from :attr:`Client.user`) |
++---------------------------------------+------------------------------------------------------------------------------+
+| ``Client.edit_role`` | :meth:`Role.edit` |
++---------------------------------------+------------------------------------------------------------------------------+
+| ``Client.edit_server`` | :meth:`Guild.edit` |
++---------------------------------------+------------------------------------------------------------------------------+
+| ``Client.estimate_pruned_members`` | :meth:`Guild.estimate_pruned_members` |
++---------------------------------------+------------------------------------------------------------------------------+
+| ``Client.get_all_emojis`` | :meth:`Client.emojis` |
++---------------------------------------+------------------------------------------------------------------------------+
+| ``Client.get_bans`` | :meth:`Guild.bans` |
++---------------------------------------+------------------------------------------------------------------------------+
+| ``Client.get_message`` | :meth:`abc.Messageable.get_message` |
++---------------------------------------+------------------------------------------------------------------------------+
+| ``Client.get_reaction_users`` | :meth:`Reaction.users` |
++---------------------------------------+------------------------------------------------------------------------------+
+| ``Client.invites_from`` | :meth:`abc.GuildChannel.invites` or :meth:`Guild.invites` |
++---------------------------------------+------------------------------------------------------------------------------+
+| ``Client.join_voice_channel`` | :meth:`VoiceChannel.connect` (see :ref:`migrating_1_0_voice`) |
++---------------------------------------+------------------------------------------------------------------------------+
+| ``Client.kick`` | :meth:`Guild.kick` or :meth:`Member.kick` |
++---------------------------------------+------------------------------------------------------------------------------+
+| ``Client.leave_server`` | :meth:`Guild.leave` |
++---------------------------------------+------------------------------------------------------------------------------+
+| ``Client.logs_from`` | :meth:`abc.Messageable.history` (see :ref:`migrating_1_0_async_iter`) |
++---------------------------------------+------------------------------------------------------------------------------+
+| ``Client.move_channel`` | :meth:`TextChannel.edit` or :meth:`VoiceChannel.edit` |
++---------------------------------------+------------------------------------------------------------------------------+
+| ``Client.move_member`` | :meth:`Member.edit` |
++---------------------------------------+------------------------------------------------------------------------------+
+| ``Client.move_role`` | :meth:`Role.edit` |
++---------------------------------------+------------------------------------------------------------------------------+
+| ``Client.pin_message`` | :meth:`Message.pin` |
++---------------------------------------+------------------------------------------------------------------------------+
+| ``Client.pins_from`` | :meth:`abc.Messageable.pins` |
++---------------------------------------+------------------------------------------------------------------------------+
+| ``Client.prune_members`` | :meth:`Guild.prune_members` |
++---------------------------------------+------------------------------------------------------------------------------+
+| ``Client.purge_from`` | :meth:`abc.Messageable.purge` |
++---------------------------------------+------------------------------------------------------------------------------+
+| ``Client.remove_reaction`` | :meth:`Message.remove_reaction` |
++---------------------------------------+------------------------------------------------------------------------------+
+| ``Client.remove_roles`` | :meth:`Member.remove_roles` |
++---------------------------------------+------------------------------------------------------------------------------+
+| ``Client.replace_roles`` | :meth:`Member.edit` |
++---------------------------------------+------------------------------------------------------------------------------+
+| ``Client.send_file`` | :meth:`abc.Messageable.send` (see :ref:`migrating_1_0_sending_messages`) |
++---------------------------------------+------------------------------------------------------------------------------+
+| ``Client.send_message`` | :meth:`abc.Messageable.send` (see :ref:`migrating_1_0_sending_messages`) |
++---------------------------------------+------------------------------------------------------------------------------+
+| ``Client.send_typing`` | :meth:`abc.Messageable.trigger_typing` (use :meth:`abc.Messageable.typing`) |
++---------------------------------------+------------------------------------------------------------------------------+
+| ``Client.server_voice_state`` | :meth:`Member.edit` |
++---------------------------------------+------------------------------------------------------------------------------+
+| ``Client.start_private_message`` | :meth:`User.create_dm` |
++---------------------------------------+------------------------------------------------------------------------------+
+| ``Client.unban`` | :meth:`Guild.unban` or :meth:`Member.unban` |
++---------------------------------------+------------------------------------------------------------------------------+
+| ``Client.unpin_message`` | :meth:`Message.unpin` |
++---------------------------------------+------------------------------------------------------------------------------+
+| ``Client.wait_for_message`` | :meth:`Client.wait_for` (see :ref:`migrating_1_0_wait_for`) |
++---------------------------------------+------------------------------------------------------------------------------+
+| ``Client.wait_for_reaction`` | :meth:`Client.wait_for` (see :ref:`migrating_1_0_wait_for`) |
++---------------------------------------+------------------------------------------------------------------------------+
+| ``Client.wait_until_login`` | Removed |
++---------------------------------------+------------------------------------------------------------------------------+
+| ``Client.wait_until_ready`` | No change |
++---------------------------------------+------------------------------------------------------------------------------+
+
+Property Changes
+~~~~~~~~~~~~~~~~~~
+
+In order to be a bit more consistent, certain things that were properties were changed to methods instead.
+
+The following are now methods instead of properties (requires parentheses):
+
+- :meth:`TextChannel.is_default`
+- :meth:`Role.is_default`
+- :meth:`Client.is_ready`
+- :meth:`Client.is_closed`
+
+Dict Value Change
+~~~~~~~~~~~~~~~~~~~~~
+
+Prior to v1.0 some aggregating properties that retrieved models would return "dict view" objects.
+
+As a consequence, when the dict would change size while you would iterate over it, a RuntimeError would
+be raised and crash the task. To alleviate this, the "dict view" objects were changed into lists.
+
+The following views were changed to a list:
+
+- :attr:`Client.guilds`
+- :attr:`Client.users` (new in v1.0)
+- :attr:`Client.emojis` (new in v1.0)
+- :attr:`Guild.channels`
+- :attr:`Guild.text_channels` (new in v1.0)
+- :attr:`Guild.voice_channels` (new in v1.0)
+- :attr:`Guild.emojis`
+- :attr:`Guild.members`
-The biggest major change is that the library has dropped support to all versions prior to
-Python 3.4.2. This was made to support ``asyncio``, in which more detail can be seen
-:issue:`in the corresponding issue <50>`. To reiterate this, the implication is that
-**python version 2.7 and 3.3 are no longer supported**.
+Voice State Changes
+~~~~~~~~~~~~~~~~~~~~~
-Below are all the other major changes from v0.9.0 to v0.10.0.
+Earlier, in v0.11.0 a :class:`VoiceState` class was added to refer to voice states along with a
+:attr:`Member.voice` attribute to refer to it.
-.. _migrating-event-registration:
+However, it was transparent to the user. In an effort to make the library save more memory, the
+voice state change is now more visible.
-Event Registration
---------------------
+The only way to access voice attributes if via the :attr:`Member.voice` attribute. Note that if
+the member does not have a voice state this attribute can be ``None``.
-All events before were registered using :meth:`Client.event`. While this is still
-possible, the events must be decorated with ``@asyncio.coroutine``.
+Quick example: ::
-Before:
+ # before
+ member.deaf
+ member.voice.voice_channel
-.. code-block:: python
+ # after
+ if member.voice: # can be None
+ member.voice.deaf
+ member.voice.channel
- @client.event
- def on_message(message):
- pass
-After:
+User and Member Type Split
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-.. code-block:: python
+In v1.0 to save memory, :class:`User` and :class:`Member` are no longer inherited. Instead, they are "flattened"
+by having equivalent properties that map out to the functional underlying :class:`User`. Thus, there is no functional
+change in how they are used. However this breaks ``isinstance`` checks and thus is something to keep in mind.
- @client.event
- @asyncio.coroutine
- def on_message(message):
- pass
+These memory savings were accomplished by having a global :class:`User` cache, and as a positive consequence you
+can now easily fetch a :class:`User` by their ID by using the new :meth:`Client.get_user`. You can also get a list
+of all :class:`User` your client can see with :attr:`Client.users`.
-Or in Python 3.5+:
+.. _migrating_1_0_channel_split:
-.. code-block:: python
+Channel Type Split
+~~~~~~~~~~~~~~~~~~~~~
- @client.event
- async def on_message(message):
- pass
+Prior to v1.0, channels were two different types, ``Channel`` and ``PrivateChannel`` with a ``is_private``
+property to help differentiate between them.
-Because there is a lot of typing, a utility decorator (:meth:`Client.async_event`) is provided
-for easier registration. For example:
+In order to save memory the channels have been split into 4 different types:
-.. code-block:: python
+- :class:`TextChannel` for guild text channels
+- :class:`VoiceChannel` for guild voice channels
+- :class:`DMChannel` for DM channels with members
+- :class:`GroupChannel` for Group DM channels with members
- @client.async_event
- def on_message(message):
- pass
+With this split came the removal of the ``is_private`` attribute. You should now use ``isinstance``.
+
+The types are split into two different :ref:`discord_api_abcs`:
+
+- :class:`abc.GuildChannel` for guild channels
+- :class:`abc.PrivateChannel` for private channels (DMs and group DMs).
+
+So to check if something is a guild channel you would do: ::
+
+ isinstance(channel, discord.abc.GuildChannel)
+
+And to check if it's a private channel you would do: ::
+
+ isinstance(channel, discord.abc.PrivateChannel)
+
+Of course, if you're looking for only a specific type you can pass that too, e.g. ::
+
+ isintance(channel, discord.TextChannel)
+
+With this type split also came event changes, which are enumerated in :ref:`migrating_1_0_event_changes`.
+
+
+Miscellaneous Model Changes
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+There were lots of other things added or removed in the models in general.
+
+They will be enumerated here.
+
+**Removed**
+
+- :meth:`Client.login` no longer accepts email and password logins.
+
+ - Use a token and ``bot=False``
+
+- ``Client.get_all_emojis``
+
+ - Use :attr:`Client.emojis` instead.
+
+- ``Client.wait_for_message`` and ``Client.wait_for_reaction`` are gone
+
+ - Use :meth:`Client.wait_for` instead.
+
+- ``Channel.voice_members``
+
+ - Use :attr:`VoiceChannel.members` instead.
+
+- ``Channel.is_private``
+
+ - Use ``isinstance`` instead with one of the :ref:`discord_api_abcs` instead.
+ - e.g. ``isinstance(channel, discord.abc.GuildChannel)`` will check if it isn't a private channel.
+
+- ``Client.accept_invite``
+
+ - There is no replacement for this one. This functionality is deprecated API wise.
+
+- ``Message.edited_timestamp``
+
+ - Use :attr:`Message.edited_at` instead.
+
+- ``Message.timestamp``
+
+ - Use :attr:`Message.created_at` instead.
+
+**Added**
+
+- :attr:`VoiceChannel.members` for fetching members connected to a voice channel.
+- :attr:`TextChannel.members` for fetching members that can see the channel.
+- :attr:`Role.members` for fetching members that have the role.
+- :attr:`Guild.text_channels` for fetching text channels only.
+- :attr:`Guild.voice_channels` for fetching voice channels only.
+- :attr:`Guild.chunked` to check member chunking status.
+- :attr:`Guild.explicit_content_filter` to fetch the content filter
+- :attr:`Guild.shard_id` to get a guild's Shard ID if you're sharding.
+- :attr:`Client.users` to get all visible :class:`User` instances.
+- :meth:`Client.get_user` to get a :class:`User` by ID.
+- :meth:`User.avatar_url_as` to get an avatar in a specific size or format.
+- :meth:`Guild.vanity_invite` to fetch the guild's vanity invite.
+- :meth:`Guild.audit_logs` to fetch the guild's audit logs.
+- :attr:`Message.webhook_id` to fetch the message's webhook ID.
+- :meth:`TextChannel.is_nsfw` to check if a text channel is NSFW.
+
+.. _migrating_1_0_sending_messages:
+
+Sending Messages
+------------------
+
+One of the changes that were done was the merger of the previous ``Client.send_message`` and ``Client.send_file``
+functionality into a single method, :meth:`~abc.Messageable.send`.
+
+Basically: ::
+
+ # before
+ await client.send_message(channel, 'Hello')
+
+ # after
+ await channel.send('Hello')
+
+This supports everything that the old ``send_message`` supported such as embeds: ::
+
+ e = discord.Embed(title='foo')
+ await channel.send('Hello', embed=e)
+
+There is a caveat with sending files however, as this functionality was expanded to support multiple
+file attachments, you must now use a :class:`File` pseudo-namedtuple to upload a single file. ::
+
+ # before
+ await client.send_file(channel, 'cool.png', filename='testing.png', content='Hello')
+ # after
+ await channel.send('Hello', file=discord.File('cool.png', 'testing.png'))
-Be aware however, that this is still a coroutine and your other functions that are coroutines must
-be decorated with ``@asyncio.coroutine`` or be ``async def``.
+This change was to facilitate multiple file uploads: ::
-.. _migrating_event_changes:
+ my_files = [
+ discord.File('cool.png', 'testing.png'),
+ discord.File(some_fp, 'cool_filename.png'),
+ ]
+
+ await channel.send('Your images:', files=my_files)
+
+.. _migrating_1_0_async_iter:
+
+Asynchronous Iterators
+------------------------
+
+Prior to v1.0, certain functions like ``Client.logs_from`` would return a different type if done in Python 3.4 or 3.5+.
+
+In v1.0, this change has been reverted and will now return a singular type meeting an abstract concept called
+:class:`AsyncIterator`.
+
+This allows you to iterate over it like normal in Python 3.5+: ::
+
+ async for msg in channel.history():
+ print(msg)
+
+Or turn it into a list for either Python 3.4 or 3.5+: ::
+
+ messages = yield from channel.history().flatten()
+ for message in messages:
+ print(messages)
+
+A handy aspect of returning :class:`AsyncIterator` is that it allows you to chain functions together such as
+:meth:`AsyncIterator.map` or :meth:`AsyncIterator.filter`: ::
+
+ async for m_id in channel.history().filter(lambda m: m.author == client.user).map(lambda m: m.id):
+ print(m_id)
+
+The functions passed to :meth:`AsyncIterator.map` or :meth:`AsyncIterator.filter` can be either coroutines or regular
+functions.
+
+You can also get single elements a la :func:`discord.utils.find` or :func:`discord.utils.get` via
+:meth:`AsyncIterator.get` or :meth:`AsyncIterator.find`: ::
+
+ my_last_message = await channel.history().get(author=client.user)
+
+The following return :class:`AsyncIterator`:
+
+- :meth:`abc.Messageable.history`
+- :meth:`Guild.audit_logs`
+- :meth:`Reaction.users`
+
+.. _migrating_1_0_event_changes:
Event Changes
--------------
-Some events in v0.9.0 were considered pretty useless due to having no separate states. The main
-events that were changed were the ``_update`` events since previously they had no context on what
-was changed.
+A lot of events have gone through some changes.
+
+Many events with ``server`` in the name where changed to use ``guild`` instead.
Before:
-.. code-block:: python
+- ``on_server_join``
+- ``on_server_remove``
+- ``on_server_update``
+- ``on_server_role_create``
+- ``on_server_role_delete``
+- ``on_server_role_update``
+- ``on_server_emojis_update``
+- ``on_server_available``
+- ``on_server_unavailable``
- def on_channel_update(channel): pass
- def on_member_update(member): pass
- def on_status(member): pass
- def on_server_role_update(role): pass
- def on_voice_state_update(member): pass
- def on_socket_raw_send(payload, is_binary): pass
+After:
+- :func:`on_guild_join`
+- :func:`on_guild_remove`
+- :func:`on_guild_update`
+- :func:`on_guild_role_create`
+- :func:`on_guild_role_delete`
+- :func:`on_guild_role_update`
+- :func:`on_guild_emojis_update`
+- :func:`on_guild_available`
+- :func:`on_guild_unavailable`
-After:
-.. code-block:: python
+The :func:`on_voice_state_update` event has received an argument change.
- def on_channel_update(before, after): pass
- def on_member_update(before, after): pass
- def on_server_role_update(before, after): pass
- def on_voice_state_update(before, after): pass
- def on_socket_raw_send(payload): pass
+Before: ::
-Note that ``on_status`` was removed. If you want its functionality, use :func:`on_member_update`.
-See :ref:`discord-api-events` for more information. Other removed events include ``on_socket_closed``, ``on_socket_receive``, and ``on_socket_opened``.
+ async def on_voice_state_update(before, after)
+After: ::
-.. _migrating-coroutines:
+ async def on_voice_state_update(member, before, after)
-Coroutines
------------
+Instead of two :class:`Member` objects, the new event takes one :class:`Member` object and two :class:`VoiceState` objects.
-The biggest change that the library went through is that almost every function in :class:`Client`
-was changed to be a `coroutine <https://docs.python.org/3/library/asyncio-task.html>`_. Functions
-that are marked as a coroutine in the documentation must be awaited from or yielded from in order
-for the computation to be done. For example...
+The :func:`on_guild_emojis_update` event has received an argument change.
-Before:
+Before: ::
-.. code-block:: python
+ async def on_guild_emojis_update(before, after)
+
+After: ::
+
+ async def on_guild_emojis_update(guild, before, after)
- client.send_message(message.channel, 'Hello')
+The first argument is now the :class:`Guild` that the emojis were updated from.
+
+The ``on_channel_`` events have received a type level split (see :ref:`migrating_1_0_channel_split`).
+
+Before:
+
+- ``on_channel_delete``
+- ``on_channel_create``
+- ``on_channel_update``
After:
-.. code-block:: python
+- :func:`on_guild_channel_delete`
+- :func:`on_guild_channel_create`
+- :func:`on_guild_channel_update`
+- :func:`on_private_channel_delete`
+- :func:`on_private_channel_create`
+- :func:`on_private_channel_update`
- yield from client.send_message(message.channel, 'Hello')
+The ``on_guild_channel_`` events correspond to :class:`abc.GuildChannel` being updated (i.e. :class:`TextChannel`
+and :class:`VoiceChannel`) and the ``on_private_channel_`` events correspond to :class:`abc.PrivateChannel` being
+updated (i.e. :class:`DMChannel` and :class:`GroupChannel`).
- # or in python 3.5+
- await client.send_message(message.channel, 'Hello')
+.. _migrating_1_0_voice:
-In order for you to ``yield from`` or ``await`` a coroutine then your function must be decorated
-with ``@asyncio.coroutine`` or ``async def``.
+Voice Changes
+---------------
-.. _migrating-iterable:
+Voice sending has gone through a complete redesign.
-Iterables
-----------
+In particular:
-For performance reasons, many of the internal data structures were changed into a dictionary to support faster
-lookup. As a consequence, this meant that some lists that were exposed via the API have changed into iterables
-and not sequences. In short, this means that certain attributes now only support iteration and not any of the
-sequence functions.
+- Connection is done through :meth:`VoiceChannel.connect` instead of ``Client.join_voice_channel``.
+- You no longer create players and operate on them (you no longer store them).
+- You instead request :class:`VoiceClient` to play an :class:`AudioSource` via :meth:`VoiceClient.play`.
+- There are different built-in :class:`AudioSource`\s
-The affected attributes are as follows:
+ - :class:`FFmpegPCMAudio` is the equivalent of ``create_ffmpeg_player``
-- :attr:`Client.servers`
-- :attr:`Client.private_channels`
-- :attr:`Server.channels`
-- :attr:`Server.members`
+- create_ffmpeg_player/create_stream_player/create_ytdl_player have all been removed
-Some examples of previously valid behaviour that is now invalid
+ - The goal is to create :class:`AudioSource` instead.
-.. code-block:: python
+- Using :meth:`VoiceClient.play` will not return an ``AudioPlayer``.
- if client.servers[0].name == "test":
- # do something
+ - Instead, it's "flattened" like :class:`User` -> :class:`Member` is.
-Since they are no longer ``list``\s, they no longer support indexing or any operation other than iterating.
-In order to get the old behaviour you should explicitly cast it to a list.
+- The ``after`` parameter now takes a single parameter (the error).
-.. code-block:: python
+Basically:
- servers = list(client.servers)
- # work with servers
+Before: ::
-.. warning::
+ vc = await client.join_voice_channel(channel)
+ player = vc.create_ffmpeg_player('testing.mp3', after=lambda: print('done'))
+ player.start()
- Due to internal changes of the structure, the order you receive the data in
- is not in a guaranteed order.
+ player.is_playing()
+ player.pause()
+ player.resume()
+ player.stop()
+ # ...
-.. _migrating-enums:
+After: ::
-Enumerations
-------------
+ vc = await channel.connect()
+ vc.play(discord.FFmpegPCMAudio('testing.mp3'), after=lambda e: print('done', e))
+ vc.is_playing()
+ vc.pause()
+ vc.resume()
+ vc.stop()
+ # ...
-Due to dropping support for versions lower than Python 3.4.2, the library can now use
-`enumerations <https://docs.python.org/3/library/enum.html>`_ in places where it makes sense.
+With the changed :class:`AudioSource` design, you can now change the source that the :class:`VoiceClient` is
+playing at runtime via :attr:`VoiceClient.source`.
-The common places where this was changed was in the server region, member status, and channel type.
+For example, you can add a :class:`PCMVolumeTransformer` to allow changing the volume: ::
-Before:
+ vc.source = discord.PCMVolumeTransformer(vc.source)
+ vc.source.volume = 0.6
-.. code-block:: python
+An added benefit of the redesign is that it will be much more resilient towards reconnections:
- server.region == 'us-west'
- member.status == 'online'
- channel.type == 'text'
+- The voice websocket will now automatically re-connect and re-do the handshake when disconnected.
+- The initial connect handshake will now retry up to 5 times so you no longer get as many ``asyncio.TimeoutError``
+- Audio will now stop and resume when a disconnect is found.
-After:
+ - This includes changing voice regions etc.
+
+
+.. _migrating_1_0_wait_for:
+
+Waiting For Events
+--------------------
+
+Prior to v1.0, the machinery for waiting for an event outside of the event itself was done through two different
+functions, ``Client.wait_for_message`` and ``Client.wait_for_reaction``. One problem with one such approach is that it did
+not allow you to wait for events outside of the ones provided by the library.
+
+In v1.0 the concept of waiting for another event has been generalised to work with any event as :meth:`Client.wait_for`.
+
+For example, to wait for a message: ::
+
+ # before
+ msg = await client.wait_for_message(author=message.author, channel=message.channel)
+
+ # after
+ def pred(m):
+ return m.author == message.author and m.channel == message.channel
+
+ msg = await client.wait_for('message', check=m)
+
+To facilitate multiple returns, :meth:`Client.wait_for` returns either a single argument, no arguments, or a tuple of
+arguments.
+
+For example, to wait for a reaction: ::
+
+ user, reaction = await client.wait_for('reaction_add', check=lambda u, r: u.id == 176995180300206080)
+
+ # use user and reaction
+
+Since this function now can return multiple arguments, the ``timeout`` parameter will now raise a ``asyncio.TimeoutError``
+when reached instead of setting the return to ``None``. For example:
.. code-block:: python
- server.region == discord.ServerRegion.us_west
- member.status = discord.Status.online
- channel.type == discord.ChannelType.text
-
-The main reason for this change was to reduce the use of finicky strings in the API as this
-could give users a false sense of power. More information can be found in the :ref:`discord-api-enums` page.
-
-.. _migrating-properties:
-
-Properties
------------
-
-A lot of function calls that returned constant values were changed into Python properties for ease of use
-in format strings.
-
-The following functions were changed into properties:
-
-+----------------------------------------+--------------------------------------+
-| Before | After |
-+----------------------------------------+--------------------------------------+
-| ``User.avatar_url()`` | :attr:`User.avatar_url` |
-+----------------------------------------+--------------------------------------+
-| ``User.mention()`` | :attr:`User.mention` |
-+----------------------------------------+--------------------------------------+
-| ``Channel.mention()`` | :attr:`Channel.mention` |
-+----------------------------------------+--------------------------------------+
-| ``Channel.is_default_channel()`` | :attr:`Channel.is_default` |
-+----------------------------------------+--------------------------------------+
-| ``Role.is_everyone()`` | :attr:`Role.is_everyone` |
-+----------------------------------------+--------------------------------------+
-| ``Server.get_default_role()`` | :attr:`Server.default_role` |
-+----------------------------------------+--------------------------------------+
-| ``Server.icon_url()`` | :attr:`Server.icon_url` |
-+----------------------------------------+--------------------------------------+
-| ``Server.get_default_channel()`` | :attr:`Server.default_channel` |
-+----------------------------------------+--------------------------------------+
-| ``Message.get_raw_mentions()`` | :attr:`Message.raw_mentions` |
-+----------------------------------------+--------------------------------------+
-| ``Message.get_raw_channel_mentions()`` | :attr:`Message.raw_channel_mentions` |
-+----------------------------------------+--------------------------------------+
-
-.. _migrating-member:
-
-Member Management
--------------------
-
-Functions that involved banning and kicking were changed.
-
-+--------------------------------+--------------------------+
-| Before | After |
-+--------------------------------+--------------------------+
-| ``Client.ban(server, user)`` | ``Client.ban(member)`` |
-+--------------------------------+--------------------------+
-| ``Client.kick(server, user)`` | ``Client.kick(member)`` |
-+--------------------------------+--------------------------+
-
-.. migrating-renames:
-
-Renamed Functions
--------------------
-
-Functions have been renamed.
-
-+------------------------------------+-------------------------------------------+
-| Before | After |
-+------------------------------------+-------------------------------------------+
-| ``Client.set_channel_permissions`` | :meth:`Client.edit_channel_permissions` |
-+------------------------------------+-------------------------------------------+
-
-All the :class:`Permissions` related attributes have been renamed and the `can_` prefix has been
-dropped. So for example, ``can_manage_messages`` has become ``manage_messages``.
-
-.. _migrating-kwargs:
-
-Forced Keyword Arguments
+ def pred(m):
+ return m.author == message.author and m.channel == message.channel
+
+ try:
+
+ msg = await client.wait_for('message', check=pred, timeout=60.0)
+ except asyncio.TimeoutError:
+ await channel.send('You took too long...')
+ else:
+ await channel.send('You said {0.content}, {0.author}.'.format(msg))
+
+Sharding
+----------
+
+The library has received significant changes on how it handles sharding and now has sharding as a first-class citizen.
+
+If using a Bot account and you want to shard your bot in a single process then you can use the :class:`AutoShardedClient`.
+
+This class allows you to use sharding without having to launch multiple processes or deal with complicated IPC.
+
+It should be noted that **the sharded client does not support user accounts**. This is due to the changes in connection
+logic and state handling.
+
+Usage is as simple as doing: ::
+
+ client = discord.AutoShardedClient()
+
+instead of using :class:`Client`.
+
+This will launch as many shards as your bot needs using the ``/gateway/bot`` endpoint, which allocates about 1000 guilds
+per shard.
+
+If you want more control over the sharding you can specify ``shard_count`` and ``shard_ids``. ::
+
+ # launch 10 shards regardless
+ client = discord.AutoShardedClient(shard_count=10)
+
+ # launch specific shard IDs in this process
+ client = discord.AutoShardedClient(shard_count=10, shard_ids=(1, 2, 5, 6))
+
+For users of the command extension, there is also :class:`~ext.commands.AutoShardedBot` which behaves similarly.
+
+Connection Improvements
-------------------------
-Since 3.0+ of Python, we can now force questions to take in forced keyword arguments. A keyword argument is when you
-explicitly specify the name of the variable and assign to it, for example: ``foo(name='test')``. Due to this support,
-some functions in the library were changed to force things to take said keyword arguments. This is to reduce errors of
-knowing the argument order and the issues that could arise from them.
+In v1.0, the auto reconnection logic has been powered up significantly.
-The following parameters are now exclusively keyword arguments:
+:meth:`Client.connect` has gained a new keyword argument, ``reconnect`` that defaults to ``True`` which controls
+the reconnect logic. When enabled, the client will automatically reconnect in all instances of your internet going
+offline or Discord going offline with exponential back-off.
-- :meth:`Client.send_message`
- - ``tts``
-- :meth:`Client.logs_from`
- - ``before``
- - ``after``
-- :meth:`Client.edit_channel_permissions`
- - ``allow``
- - ``deny``
+:meth:`Client.run` and :meth:`Client.start` gains this keyword argument as well, but for most cases you will not
+need to specify it unless turning it off.
-In the documentation you can tell if a function parameter is a forced keyword argument if it is after ``\*,``
-in the function signature.
+.. _migrating_1_0_commands:
-.. _migrating-running:
+Command Extension Changes
+--------------------------
-Running the Client
---------------------
+Due to the :ref:`migrating_1_0_model_state` changes, some of the design of the extension module had to
+undergo some design changes as well.
+
+Context Changes
+~~~~~~~~~~~~~~~~~
-In earlier versions of discord.py, ``client.run()`` was a blocking call to the main thread
-that called it. In v0.10.0 it is still a blocking call but it handles the event loop for you.
-However, in order to do that you must pass in your credentials to :meth:`Client.run`.
+In v1.0, the :class:`~ext.commands.Context` has received a lot of changes with how it's retrieved and used.
-Basically, before:
+The biggest change is that ``pass_context=True`` is now the default behaviour. Ergo:
.. code-block:: python
- client.login('token')
- client.run()
+ # before
+ @bot.command()
+ async def foo():
+ await bot.say('Hello')
-After:
+ # after
+ @bot.command()
+ async def foo(ctx):
+ await ctx.send('Hello')
+
+The reason for this is because :class:`~ext.commands.Context` now meets the requirements of :class:`abc.Messageable`. This
+makes it have similar functionality to :class:`TextChannel` or :class:`DMChannel`. Using :meth:`~ext.commands.Context.send`
+will either DM the user in a DM context or send a message in the channel it was in, similar to the old ``bot.say``
+functionality. The old helpers have been removed in favour of the new :class:`abc.Messageable` interface. See
+:ref:`migrating_1_0_removed_helpers` for more information.
+
+Since the :class:`~ext.commands.Context` is now by default passed, several shortcuts have been added:
+
+**New Shortcuts**
+
+- :attr:`~ext.commands.Context.author` is a shortcut for ``ctx.message.author``
+- :attr:`~ext.commands.Context.guild` is a shortcut for ``ctx.message.guild``
+- :attr:`~ext.commands.Context.channel` is a shortcut for ``ctx.message.channel``
+- :attr:`~ext.commands.Context.me` is a shortcut for ``ctx.message.guild.me`` or ``ctx.bot.user``.
+- :attr:`~ext.commands.Context.voice_client` is a shortcut for ``ctx.message.guild.voice_client``.
+
+Subclassing Context
+++++++++++++++++++++
+
+In v1.0, there is now the ability to subclass :class:`~ext.commands.Context` and use it instead of the default
+provided one.
+
+For example, if you want to add some functionality to the context:
.. code-block:: python
- client.run('token')
+ class MyContext(commands.Context):
+ @property
+ def secret(self):
+ return 'my secret here'
-.. warning::
+Then you can use :meth:`~ext.commands.Bot.get_context` inside :func:`on_message` with combination with
+:meth:`~ext.commands.Bot.invoke` to use your custom context:
+
+.. code-block:: python
- Like in the older ``Client.run`` function, the newer one must be the one of
- the last functions to call. This is because the function is **blocking**. Registering
- events or doing anything after :meth:`Client.run` will not execute until the function
- returns.
+ class MyBot(commands.Bot):
+ async def on_message(self, message):
+ ctx = await self.get_context(message, cls=MyContext)
+ await self.invoke(ctx)
-This is a utility function that abstracts the event loop for you. There's no need for
-the run call to be blocking and out of your control. Indeed, if you want control of the
-event loop then doing so is quite straightforward:
+Now inside your commands you will have access to your custom context:
.. code-block:: python
- import discord
- import asyncio
+ @bot.command()
+ async def secret(ctx):
+ await ctx.send(ctx.secret)
- client = discord.Client()
+.. _migrating_1_0_removed_helpers:
- @asyncio.coroutine
- def main_task():
- yield from client.login('token')
- yield from client.connect()
+Removed Helpers
++++++++++++++++++
- loop = asyncio.get_event_loop()
- try:
- loop.run_until_complete(main_task())
- except:
- loop.run_until_complete(client.logout())
- finally:
- loop.close()
+.. currentmodule:: discord.ext.commands
+
+With the new :class:`Context` changes, a lot of message sending helpers have been removed.
+
+For a full list of changes, see below:
+
++-----------------+----------------------------------------------------------+
+| Before | After |
++-----------------+----------------------------------------------------------+
+| ``Bot.say`` | :meth:`Context.send` |
++-----------------+----------------------------------------------------------+
+| ``Bot.upload`` | :meth:`Context.send` |
++-----------------+----------------------------------------------------------+
+| ``Bot.whisper`` | ``ctx.author.send`` |
++-----------------+----------------------------------------------------------+
+| ``Bot.type`` | :meth:`Context.typing` or :meth:`Context.trigger_typing` |
++-----------------+----------------------------------------------------------+
+| ``Bot.reply`` | No replacement. |
++-----------------+----------------------------------------------------------+
+
+.. currentmodule:: discord
+
+Command Changes
+~~~~~~~~~~~~~~~~~
+
+As mentioned earlier, the first command change is that ``pass_context=True`` is now the
+default, so there is no need to pass this as a parameter.
+
+Another change is the removal of ``no_pm=True``. Instead, use the new :func:`~ext.commands.guild_only` built-in
+check.
+
+The ``commands`` attribute of :class:`~ext.commands.Bot` and :class:`~ext.commands.Group` have been changed from a
+dictionary to a set that does not have aliases. To retrieve the previous dictionary behaviour, use ``all_commands`` instead.
+
+Command instances have gained a new property, :attr:`~ext.commands.Command.signature` to get the signature of command along
+with a :attr:`~ext.commands.Command.usage` attribute to override the default signature.
+
+Check Changes
+~~~~~~~~~~~~~~~
+
+Prior to v1.0, :func:`~ext.command.check`\s could only be synchronous. As of v1.0 checks can now be coroutines.
+
+Along with this change, a couple new checks were added.
+
+- :func:`~ext.commands.guild_only` replaces the old ``no_pm=True`` functionality
+- :func:`~ext.commands.is_owner` uses the :meth:`Client.application_info` endpoint by default to fetch owner ID.
+
+ - This is actually powered by a different function, :meth:`~ext.commands.Bot.is_owner`.
+ - You can set the owner ID yourself by setting :attr:`Bot.owner_id <ext.commands.Bot.owner_id>`.
+
+- :func:`~ext.commands.is_nsfw` checks if the channel the command is in is a NSFW channel.
+
+ - This is powered by the new :meth:`TextChannel.is_nsfw` check.
+
+Event Changes
+~~~~~~~~~~~~~~~
+
+All command extension events have changed.
+
+Before: ::
+
+ on_command(ctx, command)
+ on_command_completion(ctx, command)
+ on_command_error(error, ctx)
+
+After: ::
+
+ on_command(ctx)
+ on_command_completion(ctx)
+ on_command_error(ctx, error)
+
+The extraneous ``command`` parameter in :func:`~ext.commands.on_command` and :func:`~ext.commands.on_command_completion`
+have been removed. The :class:`~ext.commands.Command` instance was not kept up-to date so it was incorrect. In order to get
+the up to date :class:`~ext.commands.Command` instance, use the :attr:`Context.command <ext.commands.Context.command>`
+attribute.
+
+The error handlers, either :attr:`Command.error <ext.commands.Command.error>` or :func:`~ext.commands.on_command_error`,
+have been re-ordered to use the :class:`~ext.commands.Context` as its first parameter to be consistent with other events
+and commands.
+
+Cog Changes
+~~~~~~~~~~~~~
+
+Cog special methods have changed slightly.
+
+The previous ``__check`` special method has been renamed to ``__global_check`` to make it more clear that it's a global
+check.
+
+To complement the new ``__global_check`` there is now a new ``__local_check`` to facilitate a check that will run on
+every command in the cog.
+
+Cogs have also gained a ``__before_invoke`` and ``__after_invoke`` cog local before and after invocation hook, which
+can be seen in :ref:`migrating_1_0_before_after_hook`.
+
+The final addition is cog-local error handler, ``__error``, that is run on every command in the cog.
+
+An example cog with every special method registered is as follows: ::
+
+ class Cog:
+ def __global_check(self, ctx):
+ print('cog global check')
+ return True
+
+ async def __local_check(self, ctx):
+ print('cog local check')
+ return await ctx.bot.is_owner(ctx.author)
+
+ async def __error(self, ctx, error):
+ print('Error in {0.command.qualified_name}: {1}'.format(ctx, error))
+
+ async def __before_invoke(self, ctx):
+ print('cog local before: {0.command.qualified_name}'.format(ctx))
+
+ async def __after_invoke(self, ctx):
+ print('cog local after: {0.command.qualified_name}'.format(ctx))
+
+
+.. _migrating_1_0_before_after_hook:
+
+Before and After Invocation Hooks
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Commands have gained new before and after invocation hooks that allow you to do an action before and after a command is
+run.
+
+They take a single parameter, :class:`~ext.commands.Context` and they must be a coroutine.
+
+They are on a global, per-cog, or per-command basis.
+
+Basically: ::
+
+
+ # global hooks:
+
+ @bot.before_invoke
+ async def before_any_command(ctx):
+ # do something before a command is called
+ pass
+
+ @bot.after_invoke
+ async def after_any_command(ctx):
+ # do something after a command is called
+ pass
+
+The after invocation is hook always called, **regardless of an error in the command**. This makes it ideal for some error
+handling or clean up of certain resources such a database connection.
+
+The per-command registration is as follows: ::
+
+ @bot.command()
+ async def foo(ctx):
+ await ctx.send('foo')
+
+ @foo.before_invoke
+ async def before_foo_command(ctx):
+ # do something before the foo command is called
+ pass
+
+ @foo.after_invoke
+ async def after_foo_command(ctx):
+ # do something after the foo command is called
+ pass
+
+The special cog method for these is ``__before_invoke`` and ``__after_invoke``, e.g.: ::
+
+ class Cog:
+ async def __before_invoke(self, ctx):
+ ctx.secret_cog_data = 'foo'
+
+ async def __after_invoke(self, ctx):
+ print('{0.command} is done...'.format(ctx))
+
+ @commands.command()
+ async def foo(self, ctx):
+ await ctx.send(ctx.secret_cog_data)
+
+To check if a command failed in the after invocation hook, you can use
+:attr:`Context.command_failed <ext.commands.Context.command_failed>`.
+
+The invocation order is as follows:
+
+1. Command local before invocation hook
+2. Cog local before invocation hook
+3. Global before invocation hook
+4. The actual command
+5. Command local after invocation hooko
+6. Cog local after invocation hooko
+7. Global after invocation hooko
+
+Converter Changes
+~~~~~~~~~~~~~~~~~~~
+
+Prior to v1.0, a converter was a type hint that could be a callable that could be invoked
+with a singular argument denoting the argument passed by the user as a string.
+
+This system was eventually expanded to support a :class:`~ext.commands.Converter` system to
+allow plugging in the :class:`~ext.commands.Context` and do more complicated conversions such
+as the built-in "discord" converters.
+
+In v1.0 this converter system was revamped to allow instances of :class:`~ext.commands.Converter` derived
+classes to be passed. For consistency, the :meth:`~ext.commands.Converter.convert` method was changed to
+always be a coroutine and will now take the two arguments as parameters.
+
+Essentially, before: ::
+
+ class MyConverter(commands.Converter):
+ def convert(self):
+ return self.ctx.message.server.me
+
+After: ::
+
+ class MyConverter(commands.Converter):
+ async def convert(self, ctx, argument):
+ return ctx.me
+The command framework also got a couple new converters:
+- :class:`~ext.commands.clean_content` this is akin to :attr:`Message.clean_content` which scrubs mentions.
+- :class:`~ext.commands.UserConverter` will now appropriately convert :class:`User` only.
+- ``ChannelConverter`` is now split into two different converters
+ - :class:`~ext.commands.TextChannelConverter` for :class:`TextChannel`
+ - :class:`~ext.commands.VoiceChannelConverter` for :class:`VoiceChannel`
diff --git a/docs/migrating_to_async.rst b/docs/migrating_to_async.rst
new file mode 100644
index 00000000..c4b7e1db
--- /dev/null
+++ b/docs/migrating_to_async.rst
@@ -0,0 +1,322 @@
+:orphan:
+
+.. currentmodule:: discord
+
+.. _migrating-to-async:
+
+Migrating to v0.10.0
+======================
+
+v0.10.0 is one of the biggest breaking changes in the library due to massive
+fundamental changes in how the library operates.
+
+The biggest major change is that the library has dropped support to all versions prior to
+Python 3.4.2. This was made to support ``asyncio``, in which more detail can be seen
+:issue:`in the corresponding issue <50>`. To reiterate this, the implication is that
+**python version 2.7 and 3.3 are no longer supported**.
+
+Below are all the other major changes from v0.9.0 to v0.10.0.
+
+Event Registration
+--------------------
+
+All events before were registered using :meth:`Client.event`. While this is still
+possible, the events must be decorated with ``@asyncio.coroutine``.
+
+Before:
+
+.. code-block:: python
+
+ @client.event
+ def on_message(message):
+ pass
+
+After:
+
+.. code-block:: python
+
+ @client.event
+ @asyncio.coroutine
+ def on_message(message):
+ pass
+
+Or in Python 3.5+:
+
+.. code-block:: python
+
+ @client.event
+ async def on_message(message):
+ pass
+
+Because there is a lot of typing, a utility decorator (:meth:`Client.async_event`) is provided
+for easier registration. For example:
+
+.. code-block:: python
+
+ @client.async_event
+ def on_message(message):
+ pass
+
+
+Be aware however, that this is still a coroutine and your other functions that are coroutines must
+be decorated with ``@asyncio.coroutine`` or be ``async def``.
+
+Event Changes
+--------------
+
+Some events in v0.9.0 were considered pretty useless due to having no separate states. The main
+events that were changed were the ``_update`` events since previously they had no context on what
+was changed.
+
+Before:
+
+.. code-block:: python
+
+ def on_channel_update(channel): pass
+ def on_member_update(member): pass
+ def on_status(member): pass
+ def on_server_role_update(role): pass
+ def on_voice_state_update(member): pass
+ def on_socket_raw_send(payload, is_binary): pass
+
+
+After:
+
+.. code-block:: python
+
+ def on_channel_update(before, after): pass
+ def on_member_update(before, after): pass
+ def on_server_role_update(before, after): pass
+ def on_voice_state_update(before, after): pass
+ def on_socket_raw_send(payload): pass
+
+Note that ``on_status`` was removed. If you want its functionality, use :func:`on_member_update`.
+See :ref:`discord-api-events` for more information. Other removed events include ``on_socket_closed``, ``on_socket_receive``, and ``on_socket_opened``.
+
+
+Coroutines
+-----------
+
+The biggest change that the library went through is that almost every function in :class:`Client`
+was changed to be a `coroutine <https://docs.python.org/3/library/asyncio-task.html>`_. Functions
+that are marked as a coroutine in the documentation must be awaited from or yielded from in order
+for the computation to be done. For example...
+
+Before:
+
+.. code-block:: python
+
+ client.send_message(message.channel, 'Hello')
+
+After:
+
+.. code-block:: python
+
+ yield from client.send_message(message.channel, 'Hello')
+
+ # or in python 3.5+
+ await client.send_message(message.channel, 'Hello')
+
+In order for you to ``yield from`` or ``await`` a coroutine then your function must be decorated
+with ``@asyncio.coroutine`` or ``async def``.
+
+Iterables
+----------
+
+For performance reasons, many of the internal data structures were changed into a dictionary to support faster
+lookup. As a consequence, this meant that some lists that were exposed via the API have changed into iterables
+and not sequences. In short, this means that certain attributes now only support iteration and not any of the
+sequence functions.
+
+The affected attributes are as follows:
+
+- :attr:`Client.servers`
+- :attr:`Client.private_channels`
+- :attr:`Server.channels`
+- :attr:`Server.members`
+
+Some examples of previously valid behaviour that is now invalid
+
+.. code-block:: python
+
+ if client.servers[0].name == "test":
+ # do something
+
+Since they are no longer ``list``\s, they no longer support indexing or any operation other than iterating.
+In order to get the old behaviour you should explicitly cast it to a list.
+
+.. code-block:: python
+
+ servers = list(client.servers)
+ # work with servers
+
+.. warning::
+
+ Due to internal changes of the structure, the order you receive the data in
+ is not in a guaranteed order.
+
+Enumerations
+------------
+
+Due to dropping support for versions lower than Python 3.4.2, the library can now use
+`enumerations <https://docs.python.org/3/library/enum.html>`_ in places where it makes sense.
+
+The common places where this was changed was in the server region, member status, and channel type.
+
+Before:
+
+.. code-block:: python
+
+ server.region == 'us-west'
+ member.status == 'online'
+ channel.type == 'text'
+
+After:
+
+.. code-block:: python
+
+ server.region == discord.ServerRegion.us_west
+ member.status = discord.Status.online
+ channel.type == discord.ChannelType.text
+
+The main reason for this change was to reduce the use of finicky strings in the API as this
+could give users a false sense of power. More information can be found in the :ref:`discord-api-enums` page.
+
+Properties
+-----------
+
+A lot of function calls that returned constant values were changed into Python properties for ease of use
+in format strings.
+
+The following functions were changed into properties:
+
++----------------------------------------+--------------------------------------+
+| Before | After |
++----------------------------------------+--------------------------------------+
+| ``User.avatar_url()`` | :attr:`User.avatar_url` |
++----------------------------------------+--------------------------------------+
+| ``User.mention()`` | :attr:`User.mention` |
++----------------------------------------+--------------------------------------+
+| ``Channel.mention()`` | :attr:`Channel.mention` |
++----------------------------------------+--------------------------------------+
+| ``Channel.is_default_channel()`` | :attr:`Channel.is_default` |
++----------------------------------------+--------------------------------------+
+| ``Role.is_everyone()`` | :attr:`Role.is_everyone` |
++----------------------------------------+--------------------------------------+
+| ``Server.get_default_role()`` | :attr:`Server.default_role` |
++----------------------------------------+--------------------------------------+
+| ``Server.icon_url()`` | :attr:`Server.icon_url` |
++----------------------------------------+--------------------------------------+
+| ``Server.get_default_channel()`` | :attr:`Server.default_channel` |
++----------------------------------------+--------------------------------------+
+| ``Message.get_raw_mentions()`` | :attr:`Message.raw_mentions` |
++----------------------------------------+--------------------------------------+
+| ``Message.get_raw_channel_mentions()`` | :attr:`Message.raw_channel_mentions` |
++----------------------------------------+--------------------------------------+
+
+Member Management
+-------------------
+
+Functions that involved banning and kicking were changed.
+
++--------------------------------+--------------------------+
+| Before | After |
++--------------------------------+--------------------------+
+| ``Client.ban(server, user)`` | ``Client.ban(member)`` |
++--------------------------------+--------------------------+
+| ``Client.kick(server, user)`` | ``Client.kick(member)`` |
++--------------------------------+--------------------------+
+
+.. migrating-renames:
+
+Renamed Functions
+-------------------
+
+Functions have been renamed.
+
++------------------------------------+-------------------------------------------+
+| Before | After |
++------------------------------------+-------------------------------------------+
+| ``Client.set_channel_permissions`` | :meth:`Client.edit_channel_permissions` |
++------------------------------------+-------------------------------------------+
+
+All the :class:`Permissions` related attributes have been renamed and the `can_` prefix has been
+dropped. So for example, ``can_manage_messages`` has become ``manage_messages``.
+
+Forced Keyword Arguments
+-------------------------
+
+Since 3.0+ of Python, we can now force questions to take in forced keyword arguments. A keyword argument is when you
+explicitly specify the name of the variable and assign to it, for example: ``foo(name='test')``. Due to this support,
+some functions in the library were changed to force things to take said keyword arguments. This is to reduce errors of
+knowing the argument order and the issues that could arise from them.
+
+The following parameters are now exclusively keyword arguments:
+
+- :meth:`Client.send_message`
+ - ``tts``
+- :meth:`Client.logs_from`
+ - ``before``
+ - ``after``
+- :meth:`Client.edit_channel_permissions`
+ - ``allow``
+ - ``deny``
+
+In the documentation you can tell if a function parameter is a forced keyword argument if it is after ``\*,``
+in the function signature.
+
+.. _migrating-running:
+
+Running the Client
+--------------------
+
+In earlier versions of discord.py, ``client.run()`` was a blocking call to the main thread
+that called it. In v0.10.0 it is still a blocking call but it handles the event loop for you.
+However, in order to do that you must pass in your credentials to :meth:`Client.run`.
+
+Basically, before:
+
+.. code-block:: python
+
+ client.login('token')
+ client.run()
+
+After:
+
+.. code-block:: python
+
+ client.run('token')
+
+.. warning::
+
+ Like in the older ``Client.run`` function, the newer one must be the one of
+ the last functions to call. This is because the function is **blocking**. Registering
+ events or doing anything after :meth:`Client.run` will not execute until the function
+ returns.
+
+This is a utility function that abstracts the event loop for you. There's no need for
+the run call to be blocking and out of your control. Indeed, if you want control of the
+event loop then doing so is quite straightforward:
+
+.. code-block:: python
+
+ import discord
+ import asyncio
+
+ client = discord.Client()
+
+ @asyncio.coroutine
+ def main_task():
+ yield from client.login('token')
+ yield from client.connect()
+
+ loop = asyncio.get_event_loop()
+ try:
+ loop.run_until_complete(main_task())
+ except:
+ loop.run_until_complete(client.logout())
+ finally:
+ loop.close()
+
+
+
diff --git a/docs/quickstart.rst b/docs/quickstart.rst
new file mode 100644
index 00000000..28d2f59a
--- /dev/null
+++ b/docs/quickstart.rst
@@ -0,0 +1,76 @@
+.. _quickstart:
+
+.. currentmodule:: discord
+
+Quickstart
+============
+
+This page gives a brief introduction to the library. It assumes you have the library installed,
+if you don't check the :ref:`installing` portion.
+
+A Minimal Bot
+---------------
+
+Let's make a bot that replies to a specific message and walk you through it.
+
+It looks something like this:
+
+.. code-block:: python
+
+ import discord
+
+ client = discord.Client()
+
+ @client.event
+ async def on_ready():
+ print('We have logged in as {0.user}'.format(self))
+
+ @client.event
+ async def on_message(message):
+ if message.author == client.user:
+ return
+
+ if message.content.startswith('$hello'):
+ await message.channel.send('Hello!')
+
+ client.run('your token here')
+
+Let's name this file ``example_bot.py``. Make sure not to name it ``discord.py`` as that'll conflict
+with the library.
+
+There's a lot going on here, so let's walk you through it step by step.
+
+1. The first line just imports the library, if this raises a `ModuleNotFoundError` or `ImportError`
+ then head on over to :ref:`installing` section to properly install.
+2. Next, we create an instance of a :class:`Client`. This client is our connection to Discord.
+3. We then use the :meth:`Client.event` decorator to register an event. This library has many events.
+ Since this library is asynchronous, we do things in a "callback" style manner.
+
+ A callback is essentially a function that is called when something happens. In our case,
+ the :func:`on_ready` event is called when the bot has finished logging in and setting things
+ up and the :func:`on_message` event is called when the bot has received a message.
+4. Since the :func:`on_message` event triggers for *every* message received, we have to make
+ sure that we ignore messages from ourselves. We do this by checking if the :attr:`Message.author`
+ is the same as the :attr:`Client.user`.
+5. Afterwards, we check if the :class:`Message.content` starts with ``'$hello'``. If it is,
+ then we reply in the channel it was used in with ``'Hello!'``.
+6. Finally, we run the bot with our login token. If you need help getting your token or creating a bot,
+ look in the :ref:`discord-intro` section.
+
+
+Now that we've made a bot, we have to *run* the bot. Luckily, this is simple since this is just a
+Python script, we can run it directly.
+
+On Windows:
+
+.. code-block:: shell
+
+ $ py -3 example_bot.py
+
+On other systems:
+
+.. code-block:: shell
+
+ $ python3 example_bot.py
+
+Now you can try playing around with your basic bot.
diff --git a/docs/whats_new.rst b/docs/whats_new.rst
index 4832dd29..069138ae 100644
--- a/docs/whats_new.rst
+++ b/docs/whats_new.rst
@@ -2,12 +2,26 @@
.. _whats_new:
-What's New
+Changelog
============
This page keeps a detailed human friendly rendering of what's new and changed
in specific versions.
+.. _vp0p16p6:
+
+v0.16.6
+--------
+
+Bug Fixes
+~~~~~~~~~~
+
+- Fix issue with :meth:`Client.create_server` that made it stop working.
+- Fix main thread being blocked upon calling ``StreamPlayer.stop``.
+- Handle HEARTBEAT_ACK and resume gracefully when it occurs.
+- Fix race condition when pre-emptively rate limiting that caused releasing an already released lock.
+- Fix invalid state errors when immediately cancelling a coroutine.
+
.. _vp0p16p1:
v0.16.1