First pass at documentation reform.

This commit is contained in:
Rapptz
2017-05-12 20:14:34 -04:00
parent be2e706b2a
commit b44bba6ee6
35 changed files with 2558 additions and 682 deletions

40
docs/_static/style.css vendored Normal file
View File

@@ -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;
}

View File

@@ -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)
.. function:: on_channel_update(before, after)
Called whenever a private group DM is updated. e.g. changed name or topic.
Called whenever a channel is updated. e.g. changed name, topic, permissions.
:param before: The :class:`GroupChannel` that got updated with the old info.
:param after: The :class:`GroupChannel` that got updated with the updated info.
:param before: The :class:`Channel` that got updated with the old info.
:param after: The :class:`Channel` that got updated with the updated info.
.. function:: on_private_channel_pins_update(channel, last_pin)
.. function:: on_channel_pins_update(channel, last_pin)
Called whenever a message is pinned or unpinned from a private channel.
Called whenever a message is pinned or unpinned from a channel.
:param channel: The :class:`Channel` that had it's pins updated.
: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.
was pinned or ``None`` if there are no pins.
.. function:: on_guild_channel_delete(channel)
on_guild_channel_create(channel)
Called whenever a guild channel is deleted or created.
Note that you can get the guild from :attr:`~abc.GuildChannel.guild`.
:param channel: The :class:`abc.GuildChannel` that got created or deleted.
.. function:: on_guild_channel_update(before, after)
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.
.. 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.
: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.
.. function:: on_member_ban(member)
.. function:: on_member_ban(guild, user)
Called when a :class:`Member` gets banned from a :class:`Guild`.
Called when user gets banned from a :class:`Guild`.
You can access the guild that the member got banned from via :attr:`Member.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.
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.Snowflake
:members:
.. autoclass:: discord.abc.User
:members:
.. 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
------------

View File

@@ -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')

92
docs/discord.rst Normal file
View File

@@ -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`.

197
docs/ext/commands/api.rst Normal file
View File

@@ -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:

View File

@@ -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

View File

@@ -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')
The second way is by calling :meth:`Client.get_channel` directly: ::
await client.send_message(client.get_channel('12324234183172'), 'hello')
I'm passing IDs as integers and things are not working!
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In the library IDs must be of type ``str`` not of type ``int``. Wrap it in quotes.
channel = client.get_channel('12324234183172')
await channel.send('hello')
How do I upload an image?
~~~~~~~~~~~~~~~~~~~~~~~~~~
There are two ways of doing it. Both of which involve using :meth:`Client.send_file`.
To upload something to Discord you have to use the :class:`File` object.
The first is by opening the file and passing it directly: ::
A :class:`File` accepts two parameters, the file-like object (or file path) and the filename
to pass to Discord when uploading.
with open('my_image.png', 'rb') as f:
await client.send_file(channel, f)
If you want to upload an image it's as simple as: ::
The second is by passing the file name directly: ::
await channel.send(file=discord.File('my_file.png'))
If you have a file-like object you can do as follows: ::
with open('my_file.png', 'rb') as fp:
await channel.send(file=discord.File(fp, 'new_filename.png'))
To upload multiple files, you can use the ``files`` keyword argument instead of ``file``\: ::
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: ::
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.
await message.add_reaction('\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.
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
player = await voice.create_ytdl_player(url, after=self.foo())
other = await voice.create_ytdl_player(url, after=self.bar(10))
However the following are correct:
.. code-block:: python
player = await voice.create_ytdl_player(url, after=self.foo)
other = await voice.create_ytdl_player(url, after=lambda: self.bar(10))
Basically, these functions should not be called.
voice.play(discord.FFmpegPCMAudio(url), after=my_after)
How do I run something in the background?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
`Check the background_task.py example. <https://github.com/Rapptz/discord.py/blob/master/examples/background_task.py>`_
`Check the background_task.py example. <https://github.com/Rapptz/discord.py/blob/rewrite/examples/background_task.py>`_
How do I get a specific User/Role/Channel/Server?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
How do I get a specific model?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
There are multiple ways of doing this. If you have a specific entity's ID then you can use
There are multiple ways of doing this. If you have a specific model's ID then you can use
one of the following functions:
- :meth:`Client.get_channel`
- :meth:`Client.get_server`
- :meth:`Server.get_member`
- :meth:`Server.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:
- :meth:`abc.Messageable.get_message`
- :meth:`Client.get_user_info`
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.
specific models.
Quick example: ::
# find a guild by name
guild = discord.utils.get(client.guilds, name='My Server')
# 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``.

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

BIN
docs/images/snake.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

View File

@@ -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
Indices and tables
==================
Additional Information
-----------------------
.. toctree::
:maxdepth: 2
discord
faq
whats_new
If you still can't find what you're looking for, try in one of the following pages:
* :ref:`genindex`
* :ref:`modindex`

112
docs/intro.rst Normal file
View File

@@ -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')

File diff suppressed because it is too large Load Diff

322
docs/migrating_to_async.rst Normal file
View File

@@ -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()

76
docs/quickstart.rst Normal file
View File

@@ -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.

View File

@@ -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