Browse Source

First pass at documentation reform.

pull/572/head
Rapptz 8 years ago
parent
commit
b44bba6ee6
  1. 90
      discord/abc.py
  2. 4
      discord/channel.py
  3. 4
      discord/emoji.py
  4. 89
      discord/ext/commands/bot.py
  5. 10
      discord/ext/commands/context.py
  6. 113
      discord/ext/commands/converter.py
  7. 178
      discord/ext/commands/core.py
  8. 10
      discord/ext/commands/errors.py
  9. 30
      discord/ext/commands/formatter.py
  10. 8
      discord/guild.py
  11. 6
      discord/member.py
  12. 14
      discord/message.py
  13. 4
      discord/user.py
  14. 4
      discord/voice_client.py
  15. 40
      docs/_static/style.css
  16. 413
      docs/api.rst
  17. 10
      docs/conf.py
  18. 92
      docs/discord.rst
  19. 197
      docs/ext/commands/api.rst
  20. 13
      docs/ext/commands/index.rst
  21. 174
      docs/faq.rst
  22. BIN
      docs/images/discord_client_id.png
  23. BIN
      docs/images/discord_create_bot_user_button.png
  24. BIN
      docs/images/discord_finished_bot_user.png
  25. BIN
      docs/images/discord_new_app_button.PNG
  26. BIN
      docs/images/discord_new_app_form.png
  27. BIN
      docs/images/discord_reveal_token.png
  28. BIN
      docs/images/snake.png
  29. 48
      docs/index.rst
  30. 112
      docs/intro.rst
  31. 1113
      docs/migrating.rst
  32. 322
      docs/migrating_to_async.rst
  33. 76
      docs/quickstart.rst
  34. 16
      docs/whats_new.rst
  35. 2
      setup.py

90
discord/abc.py

@ -47,11 +47,22 @@ class _Undefined:
_undefined = _Undefined()
class Snowflake(metaclass=abc.ABCMeta):
"""An ABC that details the common operations on a Discord model.
Almost all :ref:`Discord models <discord_api_models>` meet this
abstract base class.
Attributes
-----------
id: int
The model's unique ID.
"""
__slots__ = ()
@property
@abc.abstractmethod
def created_at(self):
"""Returns the model's creation time in UTC."""
raise NotImplementedError
@classmethod
@ -68,16 +79,39 @@ class Snowflake(metaclass=abc.ABCMeta):
return NotImplemented
class User(metaclass=abc.ABCMeta):
"""An ABC that details the common operations on a Discord user.
The following implement this ABC:
- :class:`User`
- :class:`ClientUser`
- :class:`Member`
This ABC must also implement :class:`abc.Snowflake`.
Attributes
-----------
name: str
The user's username.
discriminator: str
The user's discriminator.
avatar: Optional[str]
The avatar hash the user has.
bot: bool
If the user is a bot account.
"""
__slots__ = ()
@property
@abc.abstractmethod
def display_name(self):
"""Returns the user's display name."""
raise NotImplementedError
@property
@abc.abstractmethod
def mention(self):
"""Returns a string that allows you to mention the given user."""
raise NotImplementedError
@classmethod
@ -97,6 +131,20 @@ class User(metaclass=abc.ABCMeta):
return NotImplemented
class PrivateChannel(metaclass=abc.ABCMeta):
"""An ABC that details the common operations on a private Discord channel.
The follow implement this ABC:
- :class:`DMChannel`
- :class:`GroupChannel`
This ABC must also implement :class:`abc.Snowflake`.
Attributes
-----------
me: :class:`ClientUser`
The user presenting yourself.
"""
__slots__ = ()
@classmethod
@ -115,6 +163,25 @@ class PrivateChannel(metaclass=abc.ABCMeta):
_Overwrites = namedtuple('_Overwrites', 'id allow deny type')
class GuildChannel:
"""An ABC that details the common operations on a Discord guild channel.
The follow implement this ABC:
- :class:`TextChannel`
- :class:`VoiceChannel`
This ABC must also implement :class:`abc.Snowflake`.
Attributes
-----------
name: str
The channel name.
guild: :class:`Guild`
The guild the channel belongs to.
position: int
The position in the channel list. This is a number that starts at 0.
e.g. the top channel is position 0.
"""
__slots__ = ()
def __str__(self):
@ -539,6 +606,20 @@ class GuildChannel:
return result
class Messageable(metaclass=abc.ABCMeta):
"""An ABC that details the common operations on a model that can send messages.
The follow implement this ABC:
- :class:`TextChannel`
- :class:`DMChannel`
- :class:`GroupChannel`
- :class:`User`
- :class:`Member`
- :class:`~ext.commands.Context`
This ABC must also implement :class:`abc.Snowflake`.
"""
__slots__ = ()
@asyncio.coroutine
@ -728,7 +809,7 @@ class Messageable(metaclass=abc.ABCMeta):
def history(self, *, limit=100, before=None, after=None, around=None, reverse=None):
"""Return an :class:`AsyncIterator` that enables receiving the destination's message history.
You must have Read Message History permissions to use this.
You must have :attr:`~Permissions.read_message_history` permissions to use this.
All parameters are optional.
@ -799,6 +880,13 @@ class Messageable(metaclass=abc.ABCMeta):
class Connectable(metaclass=abc.ABCMeta):
"""An ABC that details the common operations on a channel that can
connect to a voice server.
The follow implement this ABC:
- :class:`VoiceChannel`
"""
__slots__ = ()
@abc.abstractmethod

4
discord/channel.py

@ -428,7 +428,7 @@ class DMChannel(discord.abc.Messageable, Hashable):
----------
recipient: :class:`User`
The user you are participating with in the direct message channel.
me: :class:`User`
me: :class:`ClientUser`
The user presenting yourself.
id: int
The direct message channel ID.
@ -507,7 +507,7 @@ class GroupChannel(discord.abc.Messageable, Hashable):
----------
recipients: list of :class:`User`
The users you are participating with in the group channel.
me: :class:`User`
me: :class:`ClientUser`
The user presenting yourself.
id: int
The group channel ID.

4
discord/emoji.py

@ -123,7 +123,7 @@ class Emoji(Hashable):
Deletes the custom emoji.
You must have :attr:`Permissions.manage_emojis` permission to
You must have :attr:`~Permissions.manage_emojis` permission to
do this.
Guild local emotes can only be deleted by user bots.
@ -149,7 +149,7 @@ class Emoji(Hashable):
Edits the custom emoji.
You must have :attr:`Permissions.manage_emojis` permission to
You must have :attr:`~Permissions.manage_emojis` permission to
do this.
Guild local emotes can only be edited by user bots.

89
discord/ext/commands/bot.py

@ -55,7 +55,7 @@ def when_mentioned_or(*prefixes):
See Also
----------
:func:`when_mentioned`
:func:`.when_mentioned`
"""
def inner(bot, msg):
r = list(prefixes)
@ -212,17 +212,17 @@ class BotBase(GroupMixin):
def check(self, func):
"""A decorator that adds a global check to the bot.
A global check is similar to a :func:`check` that is applied
A global check is similar to a :func:`.check` that is applied
on a per command basis except it is run before any command checks
have been verified and applies to every command the bot has.
.. info::
.. note::
This function can either be a regular function or a coroutine.
Similar to a command :func:`check`\, this takes a single parameter
of type :class:`Context` and can only raise exceptions derived from
:exc:`CommandError`.
Similar to a command :func:`.check`\, this takes a single parameter
of type :class:`.Context` and can only raise exceptions derived from
:exc:`.CommandError`.
Example
---------
@ -240,7 +240,7 @@ class BotBase(GroupMixin):
def add_check(self, func):
"""Adds a global check to the bot.
This is the non-decorator interface to :meth:`check`.
This is the non-decorator interface to :meth:`.check`.
Parameters
-----------
@ -275,15 +275,15 @@ class BotBase(GroupMixin):
@asyncio.coroutine
def is_owner(self, user):
"""Checks if a :class:`User` or :class:`Member` is the owner of
"""Checks if a :class:`.User` or :class:`.Member` is the owner of
this bot.
If an :attr:`owner_id` is not set, it is fetched automatically
through the use of :meth:`application_info`.
through the use of :meth:`~.Bot.application_info`.
Parameters
-----------
user: :class:`abc.User`
user: :class:`.abc.User`
The user to check for.
"""
@ -300,11 +300,11 @@ class BotBase(GroupMixin):
called. This makes it a useful function to set up database
connections or any type of set up required.
This pre-invoke hook takes a sole parameter, a :class:`Context`.
This pre-invoke hook takes a sole parameter, a :class:`.Context`.
.. note::
The :meth:`before_invoke` and :meth:`after_invoke` hooks are
The :meth:`~.Bot.before_invoke` and :meth:`~.Bot.after_invoke` hooks are
only called if all checks and argument parsing procedures pass
without error. If any check or argument parsing procedures fail
then the hooks are not called.
@ -316,7 +316,7 @@ class BotBase(GroupMixin):
Raises
-------
discord.ClientException
:exc:`.ClientException`
The coroutine is not actually a coroutine.
"""
if not asyncio.iscoroutinefunction(coro):
@ -332,14 +332,14 @@ class BotBase(GroupMixin):
called. This makes it a useful function to clean-up database
connections or any type of clean up required.
This post-invoke hook takes a sole parameter, a :class:`Context`.
This post-invoke hook takes a sole parameter, a :class:`.Context`.
.. note::
Similar to :meth:`before_invoke`\, this is not called unless
Similar to :meth:`~.Bot.before_invoke`\, this is not called unless
checks and argument parsing procedures succeed. This hook is,
however, **always** called regardless of the internal command
callback raising an error (i.e. :exc:`CommandInvokeError`\).
callback raising an error (i.e. :exc:`.CommandInvokeError`\).
This makes it ideal for clean-up scenarios.
Parameters
@ -349,7 +349,7 @@ class BotBase(GroupMixin):
Raises
-------
discord.ClientException
:exc:`.ClientException`
The coroutine is not actually a coroutine.
"""
if not asyncio.iscoroutinefunction(coro):
@ -361,7 +361,7 @@ class BotBase(GroupMixin):
# listener registration
def add_listener(self, func, name=None):
"""The non decorator alternative to :meth:`listen`.
"""The non decorator alternative to :meth:`.listen`.
Parameters
-----------
@ -415,7 +415,7 @@ class BotBase(GroupMixin):
def listen(self, name=None):
"""A decorator that registers another function as an external
event listener. Basically this allows you to listen to multiple
events from different places e.g. such as :func:`discord.on_ready`
events from different places e.g. such as :func:`.on_ready`
The functions being listened to must be a coroutine.
@ -438,7 +438,7 @@ class BotBase(GroupMixin):
Raises
-------
discord.ClientException
:exc:`.ClientException`
The function being listened to is not a coroutine.
"""
@ -459,7 +459,7 @@ class BotBase(GroupMixin):
into a singular class that shares some state or no state at all.
The cog can also have a ``__global_check`` member function that allows
you to define a global check. See :meth:`check` for more info.
you to define a global check. See :meth:`.check` for more info.
More information will be documented soon.
@ -515,7 +515,7 @@ class BotBase(GroupMixin):
Returns
---------
Set[:class:`Command`]
Set[:class:`.Command`]
A unique set of commands without aliases that belong
to the cog.
"""
@ -675,27 +675,27 @@ class BotBase(GroupMixin):
Returns the invocation context from the message.
This is a more low-level counter-part for :meth:`process_message`
This is a more low-level counter-part for :meth:`.process_commands`
to allow users more fine grained control over the processing.
The returned context is not guaranteed to be a valid invocation
context, :attr:`Context.valid` must be checked to make sure it is.
context, :attr:`.Context.valid` must be checked to make sure it is.
If the context is not valid then it is not a valid candidate to be
invoked under :meth:`invoke`.
invoked under :meth:`~.Bot.invoke`.
Parameters
-----------
message: :class:`discord.Message`
The message to get the invocation context from.
cls: type
cls
The factory class that will be used to create the context.
By default, this is :class:`Context`. Should a custom
class be provided, it must be similar enough to :class:`Context`\'s
By default, this is :class:`.Context`. Should a custom
class be provided, it must be similar enough to :class:`.Context`\'s
interface.
Returns
--------
:class:`Context`
:class:`.Context`
The invocation context. The type of this can change via the
``cls`` parameter.
"""
@ -732,7 +732,7 @@ class BotBase(GroupMixin):
Parameters
-----------
ctx: :class:`Context`
ctx: :class:`.Context`
The invocation context to invoke.
"""
if ctx.command is not None:
@ -756,12 +756,12 @@ class BotBase(GroupMixin):
to the bot and other groups. Without this coroutine, none of the
commands will be triggered.
By default, this coroutine is called inside the :func:`on_message`
event. If you choose to override the :func:`on_message` event, then
By default, this coroutine is called inside the :func:`.on_message`
event. If you choose to override the :func:`.on_message` event, then
you should invoke this coroutine as well.
This is built using other low level tools, and is equivalent to a
call to :meth:`get_context` followed by a call to :meth:`invoke`.
call to :meth:`~.Bot.get_context` followed by a call to :meth:`~.Bot.invoke`.
Parameters
-----------
@ -782,7 +782,10 @@ class Bot(BotBase, discord.Client):
anything that you can do with a :class:`discord.Client` you can do with
this bot.
This class also subclasses :class:`GroupMixin` to provide the functionality
.. _deque: https://docs.python.org/3.4/library/collections.html#collections.deque
.. _event loop: https://docs.python.org/3/library/asyncio-eventloops.html
This class also subclasses :class:`.GroupMixin` to provide the functionality
to manage commands.
Attributes
@ -799,18 +802,18 @@ class Bot(BotBase, discord.Client):
The command prefix could also be a list or a tuple indicating that
multiple checks for the prefix should be used and the first one to
match will be the invocation prefix. You can get this prefix via
:attr:`Context.prefix`.
:attr:`.Context.prefix`.
description : str
The content prefixed into the default help message.
self_bot : bool
If ``True``, the bot will only listen to commands invoked by itself rather
than ignoring itself. If ``False`` (the default) then the bot will ignore
itself. This cannot be changed once initialised.
formatter : :class:`HelpFormatter`
formatter : :class:`.HelpFormatter`
The formatter used to format the help message. By default, it uses a
the :class:`HelpFormatter`. Check it for more info on how to override it.
the :class:`.HelpFormatter`. Check it for more info on how to override it.
If you want to change the help command completely (add aliases, etc) then
a call to :meth:`remove_command` with 'help' as the argument would do the
a call to :meth:`~.Bot.remove_command` with 'help' as the argument would do the
trick.
pm_help : Optional[bool]
A tribool that indicates if the help command should PM the user instead of
@ -823,7 +826,7 @@ class Bot(BotBase, discord.Client):
A dictionary of options to pass in for the construction of the help command.
This allows you to change the command behaviour without actually changing
the implementation of the command. The attributes will be the same as the
ones passed in the :class:`Command` constructor. Note that ``pass_context``
ones passed in the :class:`.Command` constructor. Note that ``pass_context``
will always be set to ``True`` regardless of what you pass in.
command_not_found : str
The format string used when the help command is invoked with a command that
@ -833,16 +836,16 @@ class Bot(BotBase, discord.Client):
The format string used when the help command is invoked with requests for a
subcommand but the command does not have any subcommands. Defaults to
``"Command {0.name} has no subcommands."``. The first format argument is the
:class:`Command` attempted to get a subcommand and the second is the name.
:class:`.Command` attempted to get a subcommand and the second is the name.
owner_id: Optional[int]
The ID that owns the bot. If this is not set and is then queried via
:meth:`is_owner` then it is fetched automatically using
:meth:`application_info`.
:meth:`.is_owner` then it is fetched automatically using
:meth:`~.Bot.application_info`.
"""
pass
class AutoShardedBot(BotBase, discord.AutoShardedClient):
"""This is similar to :class:`Bot` except that it is derived from
"""This is similar to :class:`.Bot` except that it is derived from
:class:`discord.AutoShardedClient` instead.
"""
pass

10
discord/ext/commands/context.py

@ -40,7 +40,7 @@ class Context(discord.abc.Messageable):
-----------
message: :class:`discord.Message`
The message that triggered the command being executed.
bot: :class:`Bot`
bot: :class:`.Bot`
The bot that contains the command being executed.
args: list
The list of transformed arguments that were passed into the command.
@ -53,13 +53,13 @@ class Context(discord.abc.Messageable):
prefix: str
The prefix that was used to invoke the command.
command
The command (i.e. :class:`Command` or its superclasses) that is being
The command (i.e. :class:`.Command` or its superclasses) that is being
invoked currently.
invoked_with: str
The command name that triggered this invocation. Useful for finding out
which alias called the command.
invoked_subcommand
The subcommand (i.e. :class:`Command` or its superclasses) that was
The subcommand (i.e. :class:`.Command` or its superclasses) that was
invoked. If no valid subcommand was invoked then this is equal to
`None`.
subcommand_passed: Optional[str]
@ -93,7 +93,7 @@ class Context(discord.abc.Messageable):
Calls a command with the arguments given.
This is useful if you want to just call the callback that a
:class:`Command` holds internally.
:class:`.Command` holds internally.
Note
------
@ -101,7 +101,7 @@ class Context(discord.abc.Messageable):
Parameters
-----------
command : :class:`Command`
command : :class:`.Command`
A command or superclass of a command that is going to be called.
\*args
The arguments to to use.

113
discord/ext/commands/converter.py

@ -46,14 +46,14 @@ def _get_from_guilds(bot, getter, argument):
return result
class Converter:
"""The base class of custom converters that require the :class:`Context`
"""The base class of custom converters that require the :class:`.Context`
to be passed to be useful.
This allows you to implement converters that function similar to the
special cased ``discord`` classes.
Classes that derive from this should override the :meth:`convert` method
to do its conversion logic. This method must be a coroutine.
Classes that derive from this should override the :meth:`~.Converter.convert`
method to do its conversion logic. This method must be a coroutine.
"""
@asyncio.coroutine
@ -62,15 +62,13 @@ class Converter:
The method to override to do conversion logic.
This can either be a coroutine or a regular function.
If an error is found while converting, it is recommended to
raise a :class:`CommandError` derived exception as it will
raise a :exc:`.CommandError` derived exception as it will
properly propagate to the error handlers.
Parameters
-----------
ctx: :class:`Context`
ctx: :class:`.Context`
The invocation context that the argument is being used in.
argument: str
The argument that is being converted.
@ -86,6 +84,20 @@ class IDConverter(Converter):
return self._id_regex.match(argument)
class MemberConverter(IDConverter):
"""Converts to a :class:`Member`.
All lookups are via the local guild. If in a DM context, then the lookup
is done by the global cache.
The lookup strategy is as follows (in order):
1. Lookup by ID.
2. Lookup by mention.
3. Lookup by name#discrim
4. Lookup by name
5. Lookup by nickname
"""
@asyncio.coroutine
def convert(self, ctx, argument):
message = ctx.message
@ -112,6 +124,17 @@ class MemberConverter(IDConverter):
return result
class UserConverter(IDConverter):
"""Converts to a :class:`User`.
All lookups are via the global user cache.
The lookup strategy is as follows (in order):
1. Lookup by ID.
2. Lookup by mention.
3. Lookup by name#discrim
4. Lookup by name
"""
@asyncio.coroutine
def convert(self, ctx, argument):
match = self._get_id_match(argument) or re.match(r'<@!?([0-9]+)>$', argument)
@ -141,6 +164,17 @@ class UserConverter(IDConverter):
return result
class TextChannelConverter(IDConverter):
"""Converts to a :class:`TextChannel`.
All lookups are via the local guild. If in a DM context, then the lookup
is done by the global cache.
The lookup strategy is as follows (in order):
1. Lookup by ID.
2. Lookup by mention.
3. Lookup by name
"""
@asyncio.coroutine
def convert(self, ctx, argument):
bot = ctx.bot
@ -170,6 +204,17 @@ class TextChannelConverter(IDConverter):
return result
class VoiceChannelConverter(IDConverter):
"""Converts to a :class:`VoiceChannel`.
All lookups are via the local guild. If in a DM context, then the lookup
is done by the global cache.
The lookup strategy is as follows (in order):
1. Lookup by ID.
2. Lookup by mention.
3. Lookup by name
"""
@asyncio.coroutine
def convert(self, ctx, argument):
bot = ctx.bot
@ -198,6 +243,17 @@ class VoiceChannelConverter(IDConverter):
return result
class ColourConverter(Converter):
"""Converts to a :class:`Colour`.
The following formats are accepted:
- ``0x<hex>``
- ``#<hex>``
- ``0x#<hex>``
- Any of the ``classmethod`` in :class:`Colour`
- The ``_`` in the name can be optionally replaced with spaces.
"""
@asyncio.coroutine
def convert(self, ctx, argument):
arg = argument.replace('0x', '').lower()
@ -208,12 +264,24 @@ class ColourConverter(Converter):
value = int(arg, base=16)
return discord.Colour(value=value)
except ValueError:
method = getattr(discord.Colour, arg, None)
method = getattr(discord.Colour, arg.replace(' ', '_'), None)
if method is None or not inspect.ismethod(method):
raise BadArgument('Colour "{}" is invalid.'.format(arg))
return method()
class RoleConverter(IDConverter):
"""Converts to a :class:`Role`.
All lookups are via the local guild. If in a DM context, then the lookup
is done by the global cache.
The lookup strategy is as follows (in order):
1. Lookup by ID.
2. Lookup by mention.
3. Lookup by name
"""
@asyncio.coroutine
def convert(self, ctx, argument):
guild = ctx.message.guild
@ -228,11 +296,16 @@ class RoleConverter(IDConverter):
return result
class GameConverter(Converter):
"""Converts to :class:`Game`."""
@asyncio.coroutine
def convert(self, ctx, argument):
return discord.Game(name=argument)
class InviteConverter(Converter):
"""Converts to a :class:`Invite`.
This is done via an HTTP request using :meth:`.Bot.get_invite`.
"""
@asyncio.coroutine
def convert(self, ctx, argument):
try:
@ -242,6 +315,18 @@ class InviteConverter(Converter):
raise BadArgument('Invite is invalid or expired') from e
class EmojiConverter(IDConverter):
"""Converts to a :class:`Emoji`.
All lookups are via the local guild. If in a DM context, then the lookup
is done by the global cache.
The lookup strategy is as follows (in order):
1. Lookup by ID.
2. Lookup by extracting ID from the emoji.
3. Lookup by name
"""
@asyncio.coroutine
def convert(self, ctx, argument):
match = self._get_id_match(argument) or re.match(r'<:[a-zA-Z0-9]+:([0-9]+)>$', argument)
@ -272,6 +357,18 @@ class EmojiConverter(IDConverter):
return result
class clean_content(Converter):
"""Converts the argument to mention scrubbed version of
said content.
This behaves similarly to :attr:`.Message.clean_content`.
Attributes
------------
fix_channel_mentions: bool
Whether to clean channel mentions.
use_nicknames: bool
Whether to use nicknames when transforming mentions.
"""
def __init__(self, *, fix_channel_mentions=False, use_nicknames=True):
self.fix_channel_mentions = fix_channel_mentions
self.use_nicknames = use_nicknames

178
discord/ext/commands/core.py

@ -88,54 +88,54 @@ class Command:
Attributes
-----------
name : str
name: str
The name of the command.
callback : coroutine
callback: coroutine
The coroutine that is executed when the command is called.
help : str
help: str
The long help text for the command.
brief : str
brief: str
The short help text for the command. If this is not specified
then the first line of the long help text is used instead.
usage : str
usage: str
A replacement for arguments in the default help text.
aliases : list
aliases: list
The list of aliases the command can be invoked under.
pass_context : bool
A boolean that indicates that the current :class:`Context` should
pass_context: bool
A boolean that indicates that the current :class:`.Context` should
be passed as the **first parameter**. Defaults to `True`.
enabled : bool
enabled: bool
A boolean that indicates if the command is currently enabled.
If the command is invoked while it is disabled, then
:exc:`DisabledCommand` is raised to the :func:`on_command_error`
:exc:`.DisabledCommand` is raised to the :func:`.on_command_error`
event. Defaults to ``True``.
parent : Optional[command]
parent: Optional[command]
The parent command that this command belongs to. ``None`` is there
isn't one.
checks
A list of predicates that verifies if the command could be executed
with the given :class:`Context` as the sole parameter. If an exception
with the given :class:`.Context` as the sole parameter. If an exception
is necessary to be thrown to signal failure, then one derived from
:exc:`CommandError` should be used. Note that if the checks fail then
:exc:`CheckFailure` exception is raised to the :func:`on_command_error`
:exc:`.CommandError` should be used. Note that if the checks fail then
:exc:`.CheckFailure` exception is raised to the :func:`.on_command_error`
event.
description : str
description: str
The message prefixed into the default help command.
hidden : bool
hidden: bool
If ``True``\, the default help command does not show this in the
help output.
rest_is_raw : bool
rest_is_raw: bool
If ``False`` and a keyword-only argument is provided then the keyword
only argument is stripped and handled as if it was a regular argument
that handles :exc:`MissingRequiredArgument` and default values in a
that handles :exc:`.MissingRequiredArgument` and default values in a
regular matter rather than passing the rest completely raw. If ``True``
then the keyword-only argument will pass in the rest of the arguments
in a completely raw matter. Defaults to ``False``.
ignore_extra : bool
ignore_extra: bool
If ``True``\, ignores extraneous strings passed to a command if all its
requirements are met (e.g. ``?foo a b c`` when only expecting ``a``
and ``b``). Otherwise :func:`on_command_error` and local error handlers
are called with :exc:`TooManyArguments`. Defaults to ``True``.
and ``b``). Otherwise :func:`.on_command_error` and local error handlers
are called with :exc:`.TooManyArguments`. Defaults to ``True``.
"""
def __init__(self, name, callback, **kwargs):
self.name = name
@ -418,7 +418,7 @@ class Command:
Parameters
-----------
ctx: :class:`Context`
ctx: :class:`.Context`
The invocation context to reset the cooldown under.
"""
if self._buckets.valid:
@ -439,8 +439,8 @@ class Command:
def error(self, coro):
"""A decorator that registers a coroutine as a local error handler.
A local error handler is an :func:`on_command_error` event limited to
a single command. However, the :func:`on_command_error` is still
A local error handler is an :func:`.on_command_error` event limited to
a single command. However, the :func:`.on_command_error` is still
invoked afterwards as the catch-all.
Parameters
@ -463,13 +463,13 @@ class Command:
def before_invoke(self, coro):
"""A decorator that registers a coroutine as a pre-invoke hook.
A pre-invoke hook is called directly before :meth:`invoke` is
A pre-invoke hook is called directly before the command is
called. This makes it a useful function to set up database
connections or any type of set up required.
This pre-invoke hook takes a sole parameter, a :class:`Context`.
This pre-invoke hook takes a sole parameter, a :class:`.Context`.
See :meth:`Bot.before_invoke` for more info.
See :meth:`.Bot.before_invoke` for more info.
Parameters
-----------
@ -478,7 +478,7 @@ class Command:
Raises
-------
discord.ClientException
:exc:`.ClientException`
The coroutine is not actually a coroutine.
"""
if not asyncio.iscoroutinefunction(coro):
@ -490,13 +490,13 @@ class Command:
def after_invoke(self, coro):
"""A decorator that registers a coroutine as a post-invoke hook.
A post-invoke hook is called directly after :meth:`invoke` is
A post-invoke hook is called directly after the command is
called. This makes it a useful function to clean-up database
connections or any type of clean up required.
This post-invoke hook takes a sole parameter, a :class:`Context`.
This post-invoke hook takes a sole parameter, a :class:`.Context`.
See :meth:`Bot.after_invoke` for more info.
See :meth:`.Bot.after_invoke` for more info.
Parameters
-----------
@ -505,7 +505,7 @@ class Command:
Raises
-------
discord.ClientException
:exc:`.ClientException`
The coroutine is not actually a coroutine.
"""
if not asyncio.iscoroutinefunction(coro):
@ -577,11 +577,11 @@ class Command:
"""|coro|
Checks if the command can be executed by checking all the predicates
inside the :attr:`checks` attribute.
inside the :attr:`.checks` attribute.
Parameters
-----------
ctx: :class:`Context`
ctx: :class:`.Context`
The ctx of the command currently being invoked.
Returns
@ -613,12 +613,12 @@ class Command:
class GroupMixin:
"""A mixin that implements common functionality for classes that behave
similar to :class:`Group` and are allowed to register commands.
similar to :class:`.Group` and are allowed to register commands.
Attributes
-----------
all_commands: dict
A mapping of command name to :class:`Command` or superclass
A mapping of command name to :class:`.Command` or superclass
objects.
"""
def __init__(self, **kwargs):
@ -627,7 +627,7 @@ class GroupMixin:
@property
def commands(self):
"""Set[:class:`Command`]: A unique set of commands without aliases that are registered."""
"""Set[:class:`.Command`]: A unique set of commands without aliases that are registered."""
return set(self.all_commands.values())
def recursively_remove_all_commands(self):
@ -637,11 +637,11 @@ class GroupMixin:
self.remove_command(command.name)
def add_command(self, command):
"""Adds a :class:`Command` or its superclasses into the internal list
"""Adds a :class:`.Command` or its superclasses into the internal list
of commands.
This is usually not called, instead the :meth:`command` or
:meth:`group` shortcut decorators are used instead.
This is usually not called, instead the :meth:`~.GroupMixin.command` or
:meth:`~.GroupMixin.group` shortcut decorators are used instead.
Parameters
-----------
@ -650,10 +650,10 @@ class GroupMixin:
Raises
-------
discord.ClientException
:exc:`.ClientException`
If the command is already registered.
TypeError
If the command passed is not a subclass of :class:`Command`.
If the command passed is not a subclass of :class:`.Command`.
"""
if not isinstance(command, Command):
@ -672,19 +672,19 @@ class GroupMixin:
self.all_commands[alias] = command
def remove_command(self, name):
"""Remove a :class:`Command` or subclasses from the internal list
"""Remove a :class:`.Command` or subclasses from the internal list
of commands.
This could also be used as a way to remove aliases.
Parameters
-----------
name : str
name: str
The name of the command to remove.
Returns
--------
Command or subclass
:class:`.Command` or subclass
The command that was removed. If the name is not valid then
`None` is returned instead.
"""
@ -711,7 +711,7 @@ class GroupMixin:
yield from command.walk_commands()
def get_command(self, name):
"""Get a :class:`Command` or subclasses from the internal list
"""Get a :class:`.Command` or subclasses from the internal list
of commands.
This could also be used as a way to get aliases.
@ -745,8 +745,8 @@ class GroupMixin:
return obj
def command(self, *args, **kwargs):
"""A shortcut decorator that invokes :func:`command` and adds it to
the internal command list via :meth:`add_command`.
"""A shortcut decorator that invokes :func:`.command` and adds it to
the internal command list via :meth:`~.GroupMixin.add_command`.
"""
def decorator(func):
result = command(*args, **kwargs)(func)
@ -756,8 +756,8 @@ class GroupMixin:
return decorator
def group(self, *args, **kwargs):
"""A shortcut decorator that invokes :func:`group` and adds it to
the internal command list via :meth:`add_command`.
"""A shortcut decorator that invokes :func:`.group` and adds it to
the internal command list via :meth:`~.GroupMixin.add_command`.
"""
def decorator(func):
result = group(*args, **kwargs)(func)
@ -770,12 +770,12 @@ class Group(GroupMixin, Command):
"""A class that implements a grouping protocol for commands to be
executed as subcommands.
This class is a subclass of :class:`Command` and thus all options
valid in :class:`Command` are valid in here as well.
This class is a subclass of :class:`.Command` and thus all options
valid in :class:`.Command` are valid in here as well.
Attributes
-----------
invoke_without_command : bool
invoke_without_command: bool
Indicates if the group callback should begin parsing and
invocation only if no subcommand was found. Useful for
making it an error handling function to tell the user that
@ -820,25 +820,25 @@ class Group(GroupMixin, Command):
# Decorators
def command(name=None, cls=None, **attrs):
"""A decorator that transforms a function into a :class:`Command`
or if called with :func:`group`, :class:`Group`.
"""A decorator that transforms a function into a :class:`.Command`
or if called with :func:`.group`, :class:`.Group`.
By default the ``help`` attribute is received automatically from the
docstring of the function and is cleaned up with the use of
``inspect.cleandoc``. If the docstring is ``bytes``, then it is decoded
into ``str`` using utf-8 encoding.
All checks added using the :func:`check` & co. decorators are added into
All checks added using the :func:`.check` & co. decorators are added into
the function. There is no way to supply your own checks through this
decorator.
Parameters
-----------
name : str
name: str
The name to create the command with. By default this uses the
function name unchanged.
cls
The class to construct with. By default this is :class:`Command`.
The class to construct with. By default this is :class:`.Command`.
You usually do not change this.
attrs
Keyword arguments to pass into the construction of the class denoted
@ -886,28 +886,28 @@ def command(name=None, cls=None, **attrs):
return decorator
def group(name=None, **attrs):
"""A decorator that transforms a function into a :class:`Group`.
"""A decorator that transforms a function into a :class:`.Group`.
This is similar to the :func:`command` decorator but creates a
:class:`Group` instead of a :class:`Command`.
This is similar to the :func:`.command` decorator but creates a
:class:`.Group` instead of a :class:`.Command`.
"""
return command(name=name, cls=Group, **attrs)
def check(predicate):
"""A decorator that adds a check to the :class:`Command` or its
subclasses. These checks could be accessed via :attr:`Command.checks`.
"""A decorator that adds a check to the :class:`.Command` or its
subclasses. These checks could be accessed via :attr:`.Command.checks`.
These checks should be predicates that take in a single parameter taking
a :class:`Context`. If the check returns a ``False``\-like value then
during invocation a :exc:`CheckFailure` exception is raised and sent to
the :func:`on_command_error` event.
a :class:`.Context`. If the check returns a ``False``\-like value then
during invocation a :exc:`.CheckFailure` exception is raised and sent to
the :func:`.on_command_error` event.
If an exception should be thrown in the predicate then it should be a
subclass of :exc:`CommandError`. Any exception not subclassed from it
subclass of :exc:`.CommandError`. Any exception not subclassed from it
will be propagated while those subclassed will be sent to
:func:`on_command_error`.
:func:`.on_command_error`.
.. info::
.. note::
These functions can either be regular functions or coroutines.
@ -960,7 +960,7 @@ def check(predicate):
return decorator
def has_role(name):
"""A :func:`check` that is added that checks if the member invoking the
"""A :func:`.check` that is added that checks if the member invoking the
command has the role specified via the name specified.
The name is case sensitive and must be exact. No normalisation is done in
@ -971,7 +971,7 @@ def has_role(name):
Parameters
-----------
name : str
name: str
The name of the role to check.
"""
@ -985,11 +985,11 @@ def has_role(name):
return check(predicate)
def has_any_role(*names):
"""A :func:`check` that is added that checks if the member invoking the
"""A :func:`.check` that is added that checks if the member invoking the
command has **any** of the roles specified. This means that if they have
one out of the three roles specified, then this check will return `True`.
Similar to :func:`has_role`\, the names passed in must be exact.
Similar to :func:`.has_role`\, the names passed in must be exact.
Parameters
-----------
@ -1015,11 +1015,11 @@ def has_any_role(*names):
return check(predicate)
def has_permissions(**perms):
"""A :func:`check` that is added that checks if the member has any of
"""A :func:`.check` that is added that checks if the member has any of
the permissions necessary.
The permissions passed in must be exactly like the properties shown under
:class:`discord.Permissions`.
:class:`.discord.Permissions`.
Parameters
------------
@ -1045,7 +1045,7 @@ def has_permissions(**perms):
return check(predicate)
def bot_has_role(name):
"""Similar to :func:`has_role` except checks if the bot itself has the
"""Similar to :func:`.has_role` except checks if the bot itself has the
role.
"""
@ -1059,7 +1059,7 @@ def bot_has_role(name):
return check(predicate)
def bot_has_any_role(*names):
"""Similar to :func:`has_any_role` except checks if the bot itself has
"""Similar to :func:`.has_any_role` except checks if the bot itself has
any of the roles listed.
"""
def predicate(ctx):
@ -1072,7 +1072,7 @@ def bot_has_any_role(*names):
return check(predicate)
def bot_has_permissions(**perms):
"""Similar to :func:`has_permissions` except checks if the bot itself has
"""Similar to :func:`.has_permissions` except checks if the bot itself has
the permissions listed.
"""
def predicate(ctx):
@ -1083,12 +1083,12 @@ def bot_has_permissions(**perms):
return check(predicate)
def guild_only():
"""A :func:`check` that indicates this command must only be used in a
"""A :func:`.check` that indicates this command must only be used in a
guild context only. Basically, no private messages are allowed when
using the command.
This check raises a special exception, :exc:`NoPrivateMessage`
that is derived from :exc:`CheckFailure`.
This check raises a special exception, :exc:`.NoPrivateMessage`
that is derived from :exc:`.CheckFailure`.
"""
def predicate(ctx):
@ -1099,13 +1099,13 @@ def guild_only():
return check(predicate)
def is_owner():
"""A :func:`check` that checks if the person invoking this command is the
"""A :func:`.check` that checks if the person invoking this command is the
owner of the bot.
This is powered by :meth:`Bot.is_owner`.
This is powered by :meth:`.Bot.is_owner`.
This check raises a special exception, :exc:`NotOwner` that is derived
from :exc:`CheckFailure`.
This check raises a special exception, :exc:`.NotOwner` that is derived
from :exc:`.CheckFailure`.
"""
@asyncio.coroutine
@ -1117,13 +1117,13 @@ def is_owner():
return check(predicate)
def is_nsfw():
"""A :func:`check` that checks if the channel is a NSFW channel."""
"""A :func:`.check` that checks if the channel is a NSFW channel."""
def pred(ctx):
return isinstance(ctx.channel, discord.TextChannel) and ctx.channel.is_nsfw()
return check(pred)
def cooldown(rate, per, type=BucketType.default):
"""A decorator that adds a cooldown to a :class:`Command`
"""A decorator that adds a cooldown to a :class:`.Command`
or its subclasses.
A cooldown allows a command to only be used a specific amount
@ -1137,8 +1137,8 @@ def cooldown(rate, per, type=BucketType.default):
- ``BucketType.guild`` for a per-guild basis.
- ``BucketType.channel`` for a per-channel basis.
If a cooldown is triggered, then :exc:`CommandOnCooldown` is triggered in
:func:`on_command_error` and the local error handler.
If a cooldown is triggered, then :exc:`.CommandOnCooldown` is triggered in
:func:`.on_command_error` and the local error handler.
A command can only have a single cooldown.

10
discord/ext/commands/errors.py

@ -38,7 +38,7 @@ class CommandError(DiscordException):
This exception and exceptions derived from it are handled
in a special way as they are caught and passed into a special event
from :class:`Bot`\, :func:`on_command_error`.
from :class:`.Bot`\, :func:`on_command_error`.
"""
def __init__(self, message=None, *args):
if message is not None:
@ -52,7 +52,7 @@ class UserInputError(CommandError):
"""The base exception type for errors that involve errors
regarding user input.
This inherits from :exc:`CommandError`.
This inherits from :exc:`.CommandError`.
"""
pass
@ -80,7 +80,7 @@ class MissingRequiredArgument(UserInputError):
class TooManyArguments(UserInputError):
"""Exception raised when the command was passed too many arguments and its
:attr:`Command.ignore_extra` attribute was not set to ``True``.
:attr:`.Command.ignore_extra` attribute was not set to ``True``.
"""
pass
@ -91,7 +91,7 @@ class BadArgument(UserInputError):
pass
class CheckFailure(CommandError):
"""Exception raised when the predicates in :attr:`Command.checks` have failed."""
"""Exception raised when the predicates in :attr:`.Command.checks` have failed."""
pass
class NoPrivateMessage(CheckFailure):
@ -128,7 +128,7 @@ class CommandOnCooldown(CommandError):
-----------
cooldown: Cooldown
A class with attributes ``rate``, ``per``, and ``type`` similar to
the :func:`cooldown` decorator.
the :func:`.cooldown` decorator.
retry_after: float
The amount of seconds to wait before you can retry again.
"""

30
discord/ext/commands/formatter.py

@ -127,19 +127,19 @@ class HelpFormatter:
"""The default base implementation that handles formatting of the help
command.
To override the behaviour of the formatter, :meth:`format`
To override the behaviour of the formatter, :meth:`~.HelpFormatter.format`
should be overridden. A number of utility functions are provided for use
inside that method.
Parameters
Attributes
-----------
show_hidden : bool
show_hidden: bool
Dictates if hidden commands should be shown in the output.
Defaults to ``False``.
show_check_failure : bool
Dictates if commands that have their :attr:`Command.checks` failed
show_check_failure: bool
Dictates if commands that have their :attr:`.Command.checks` failed
shown. Defaults to ``False``.
width : int
width: int
The maximum number of characters that fit in a line.
Defaults to 80.
"""
@ -149,15 +149,15 @@ class HelpFormatter:
self.show_check_failure = show_check_failure
def has_subcommands(self):
"""bool : Specifies if the command has subcommands."""
"""bool: Specifies if the command has subcommands."""
return isinstance(self.command, GroupMixin)
def is_bot(self):
"""bool : Specifies if the command being formatted is the bot itself."""
"""bool: Specifies if the command being formatted is the bot itself."""
return self.command is self.context.bot
def is_cog(self):
"""bool : Specifies if the command being formatted is actually a cog."""
"""bool: Specifies if the command being formatted is actually a cog."""
return not self.is_bot() and not isinstance(self.command, Command)
def shorten(self, text):
@ -168,7 +168,7 @@ class HelpFormatter:
@property
def max_name_size(self):
"""int : Returns the largest name length of a command or if it has subcommands
"""int: Returns the largest name length of a command or if it has subcommands
the largest subcommand name."""
try:
commands = self.command.all_commands if not self.is_cog() else self.context.bot.all_commands
@ -202,8 +202,8 @@ class HelpFormatter:
@asyncio.coroutine
def filter_command_list(self):
"""Returns a filtered list of commands based on the two attributes
provided, :attr:`show_check_failure` and :attr:`show_hidden`. Also
filters based on if :meth:`is_cog` is valid.
provided, :attr:`show_check_failure` and :attr:`show_hidden`.
Also filters based on if :meth:`~.HelpFormatter.is_cog` is valid.
Returns
--------
@ -262,13 +262,13 @@ class HelpFormatter:
def format_help_for(self, context, command_or_bot):
"""Formats the help page and handles the actual heavy lifting of how
the help command looks like. To change the behaviour, override the
:meth:`format` method.
:meth:`~.HelpFormatter.format` method.
Parameters
-----------
context : :class:`Context`
context: :class:`.Context`
The context of the invoked help command.
command_or_bot : :class:`Command` or :class:`Bot`
command_or_bot: :class:`.Command` or :class:`.Bot`
The bot or command that we are getting the help of.
Returns

8
discord/guild.py

@ -566,7 +566,7 @@ class Guild(Hashable):
Edits the guild.
You must have the :attr:`Permissions.manage_guild` permission
You must have the :attr:`~Permissions.manage_guild` permission
to edit the guild.
Parameters
@ -671,7 +671,7 @@ class Guild(Hashable):
that got banned along with a ``reason`` field specifying
why the user was banned that could be set to ``None``.
You must have :attr:`Permissions.ban_members` permission
You must have :attr:`~Permissions.ban_members` permission
to get this information.
Raises
@ -701,7 +701,7 @@ class Guild(Hashable):
The inactive members are denoted if they have not logged on in
``days`` number of days and they have no roles.
You must have the :attr:`Permissions.kick_members` permission
You must have the :attr:`~Permissions.kick_members` permission
to use this.
To check how many members you would prune without actually pruning,
@ -775,7 +775,7 @@ class Guild(Hashable):
Returns a list of all active instant invites from the guild.
You must have :attr:`Permissions.manage_guild` to get this information.
You must have :attr:`~Permissions.manage_guild` to get this information.
Raises
-------

6
discord/member.py

@ -458,7 +458,7 @@ class Member(discord.abc.Messageable):
Moves a member to a new voice channel (they must be connected first).
You must have the :attr:`Permissions.move_members` permission to
You must have the :attr:`~Permissions.move_members` permission to
use this.
This raises the same exceptions as :meth:`edit`.
@ -478,7 +478,7 @@ class Member(discord.abc.Messageable):
Gives the member a number of :class:`Role`\s.
You must have the :attr:`Permissions.manage_roles` permission to
You must have the :attr:`~Permissions.manage_roles` permission to
use this.
Parameters
@ -505,7 +505,7 @@ class Member(discord.abc.Messageable):
Removes :class:`Role`\s from this member.
You must have the :attr:`Permissions.manage_roles` permission to
You must have the :attr:`~Permissions.manage_roles` permission to
use this.
Parameters

14
discord/message.py

@ -413,7 +413,7 @@ class Message:
Deletes the message.
Your own messages could be deleted without any proper permissions. However to
delete other people's messages, you need the :attr:`Permissions.manage_messages`
delete other people's messages, you need the :attr:`~Permissions.manage_messages`
permission.
Parameters
@ -475,7 +475,7 @@ class Message:
def pin(self):
"""|coro|
Pins the message. You must have :attr:`Permissions.manage_messages`
Pins the message. You must have :attr:`~Permissions.manage_messages`
permissions to do this in a non-private channel context.
Raises
@ -496,7 +496,7 @@ class Message:
def unpin(self):
"""|coro|
Unpins the message. You must have :attr:`Permissions.manage_messages`
Unpins the message. You must have :attr:`~Permissions.manage_messages`
permissions to do this in a non-private channel context.
Raises
@ -520,8 +520,8 @@ class Message:
The emoji may be a unicode emoji or a custom guild :class:`Emoji`.
You must have the :attr:`Permissions.add_reactions` permission to
add new reactions to a message.
You must have the :attr:`~Permissions.add_reactions` and
:attr:`~Permissions.read_message_history` permissions to use this.
Parameters
------------
@ -560,7 +560,7 @@ class Message:
The emoji may be a unicode emoji or a custom guild :class:`Emoji`.
If the reaction is not your own (i.e. ``member`` parameter is not you) then
the :attr:`Permissions.manage_messages` permission is needed.
the :attr:`~Permissions.manage_messages` permission is needed.
The ``member`` parameter must represent a member and meet
the :class:`abc.Snowflake` abc.
@ -601,7 +601,7 @@ class Message:
Removes all the reactions from the message.
You need :attr:`Permissions.manage_messages` permission
You need :attr:`~Permissions.manage_messages` permission
to use this.
Raises

4
discord/user.py

@ -197,7 +197,7 @@ class ClientUser(BaseUser):
The user's unique ID.
discriminator: str
The user's discriminator. This is given when the username has conflicts.
avatar: str
avatar: Optional[str]
The avatar hash the user has. Could be None.
bot: bool
Specifies if the user is a bot account.
@ -404,7 +404,7 @@ class User(BaseUser, discord.abc.Messageable):
The user's unique ID.
discriminator: str
The user's discriminator. This is given when the username has conflicts.
avatar: str
avatar: Optional[str]
The avatar hash the user has. Could be None.
bot: bool
Specifies if the user is a bot account.

4
discord/voice_client.py

@ -62,8 +62,8 @@ from .player import AudioPlayer, AudioSource
class VoiceClient:
"""Represents a Discord voice connection.
This client is created solely through :meth:`Client.join_voice_channel`
and its only purpose is to transmit voice.
You do not create these, you typically get them from
e.g. :meth:`VoiceChannel.connect`.
Warning
--------

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

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

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

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

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

13
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

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

BIN
docs/images/discord_client_id.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

BIN
docs/images/discord_create_bot_user_button.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

BIN
docs/images/discord_finished_bot_user.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

BIN
docs/images/discord_new_app_button.PNG

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

BIN
docs/images/discord_new_app_form.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

BIN
docs/images/discord_reveal_token.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

BIN
docs/images/snake.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

48
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`

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

1113
docs/migrating.rst

File diff suppressed because it is too large

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

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

16
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

2
setup.py

@ -9,6 +9,7 @@ with open('requirements.txt') as f:
if on_rtd:
requirements.append('sphinxcontrib-napoleon')
requirements.append('sphinxcontrib-asyncio')
version = ''
with open('discord/__init__.py') as f:
@ -35,6 +36,7 @@ with open('README.md') as f:
extras_require = {
'voice': ['PyNaCl==1.0.1'],
'docs': ['sphinxcontrib-asyncio']
}
setup(name='discord.py',

Loading…
Cancel
Save