An abstraction over a :class:disco.api.http.HTTPClient, which composes
+requests from provided data, and fits models with the returned data. The APIClient
+is the only path to the API used within models/other interfaces, and it's
+the recommended path for all third-party users/implementations.
+
Args
+
+
+
+
Name
+
Type
+
Description
+
+
+
+
+
token
+
str
+
The Discord authentication token (without prefixes) to be used for all HTTP requests.
+
+
+
client
+
Optional[:class:`disco.client.Client`]
+
The Disco client this APIClient is a member of. This is used when constructing and fitting models from response data.
+
+
+
+
Attributes
+
+
+
+
Name
+
Type
+
Description
+
+
+
+
+
client
+
Optional[:class:`disco.client.Client`]
+
The Disco client this APIClient is a member of.
+
+
+
http
+
:class:`disco.http.HTTPClient`
+
The HTTPClient this APIClient uses for all requests.
+
+
+
+
Functions
+
init(self, token, client)
+
_after_requests(self, response)
+
capture(self)
+
Context manager which captures all requests made, returning a special
+Responses list, which can be used to introspect raw API responses. This
+method is a low-level utility which should only be used by experienced users.
HTTPMethod = Enum(
+ GET = GET,
+ POST = POST,
+ PUT = PUT,
+ PATCH = PATCH,
+ DELETE = DELETE)
+
+
Classes
+
Routes
+
Simple Python object-enum of all method/url route combinations available to
+this client.
+
APIResponse
+
Functions
+
init(self)
+
APIException
+
Inherits From Exception
+
Exception thrown when an HTTP-client level error occurs. Usually this will
+be a non-success status-code, or a transient network issue.
+
Attributes
+
+
+
+
Name
+
Type
+
Description
+
+
+
+
+
status_code
+
int
+
The status code returned by the API for the request that triggered this error.
+
+
+
+
Functions
+
init(self, response, retries)
+
HTTPClient
+
Inherits From LoggingClass
+
A simple HTTP client which wraps the requests library, adding support for
+Discords rate-limit headers, authorization, and request/response validation.
+
Functions
+
init(self, token, after_request)
+
call(self, route, args,**kwargs)
+
call(self, route, args,**kwargs)
+
Makes a request to the given route (as specified in
+:class:disco.api.http.Routes) with a set of URL arguments, and keyword
+arguments passed to requests.
+
Returns
+
The response object for the request
+
Raises
+
Raised when an unrecoverable error occurs, or when we've exhausted
+the number of retries.
+
Parameters
+
+
+
+
Name
+
Type
+
Description
+
+
+
+
+
route
+
tuple(:class:`HTTPMethod`, str)
+
The method.URL combination that when compiled with URL arguments creates a requestable route which the HTTPClient will make the request too.
+
+
+
args
+
dict(str, str)
+
A dictionary of URL arguments that will be compiled with the raw URL to create the requestable route. The HTTPClient uses this to track rate limits as well.
+
+
+
kwargs
+
dict
+
Keyword arguments that will be passed along to the requests library
+
+
+
+
random_backoff(</code>)
+
Returns a random backoff (in milliseconds) to be used for any error the
+client suspects is transient. Will always return a value between 500 and
+5000 milliseconds.
+
:returns: a random backoff in milliseconds
+:rtype: float
An object which stores ratelimit state for a given method/url route
+combination (as specified in :class:disco.api.http.Routes).
+
Parameters
+
+
+
+
Name
+
Type
+
Description
+
+
+
+
+
route
+
tuple(HTTPMethod, str)
+
The route which this RouteState is for.
+
+
+
response
+
:class:`requests.Response`
+
The response object for the last request made to the route, should contain the standard rate limit headers.
+
+
+
+
Attributes
+
+
+
+
Name
+
Type
+
Description
+
+
+
+
+
route
+
tuple(HTTPMethod, str)
+
The route which this RouteState is for.
+
+
+
remaining
+
int
+
The number of remaining requests to the route before the rate limit will be hit, triggering a 429 response.
+
+
+
reset_time
+
int
+
A unix epoch timestamp (in seconds) after which this rate limit is reset
+
+
+
event
+
:class:`gevent.event.Event`
+
An event that is used to block all requests while a route is in the cooldown stage.
+
+
+
+
Functions
+
init(self, route, response)
+
repr(self)
+
chilled(self)
+
Whether this route is currently being cooldown (aka waiting until reset_time).
+
next_will_ratelimit(self)
+
Whether the next request to the route (at this moment in time) will
+trigger the rate limit.
+
update(self, response)
+
Updates this route with a given Requests response object. Its expected
+the response has the required headers, however in the case it doesn't
+this function has no effect.
+
wait(self, timeout)
+
Waits until this route is no longer under a cooldown.
+
Returns
+
The duration we waited for, in seconds or zero if we didn't have to
+wait at all.
+
cooldown(self)
+
Waits for the current route to be cooled-down (aka waiting until reset time).
+
RateLimiter
+
Inherits From LoggingClass
+
A in-memory store of ratelimit states for all routes we've ever called.
+
Attributes
+
+
+
+
Name
+
Type
+
Description
+
+
+
+
+
states
+
dict(tuple(HTTPMethod, str), :class:`RouteState`)
+
Contains a :class:`RouteState` for each route the RateLimiter is currently tracking.
+
+
+
+
Functions
+
init(self)
+
check(self, route)
+
Checks whether a given route can be called. This function will return
+immediately if no rate-limit cooldown is being imposed for the given
+route, or will wait indefinitely until the route is finished being
+cooled down. This function should be called before making a request to
+the specified route.
+
Returns
+
The number of seconds we had to wait for this rate limit, or zero
+if no time was waited.
+
Parameters
+
+
+
+
Name
+
Type
+
Description
+
+
+
+
+
route
+
tuple(HTTPMethod, str)
+
The route that will be checked.
+
+
+
+
_check(self, route)
+
update(self, route, response)
+
Updates the given routes state with the rate-limit headers inside the
+response from a previous call to the route.
+
Parameters
+
+
+
+
Name
+
Type
+
Description
+
+
+
+
+
route
+
tuple(HTTPMethod, str)
+
The route that will be updated.
+
+
+
response
+
:class:`requests.Response`
+
The response object for the last request to the route, whose headers will be used to update the routes rate limit state.
An object which is used to configure and define the runtime configuration for
+a bot.
+
Attributes
+
+
+
+
Name
+
Type
+
Description
+
+
+
+
+
levels
+
dict(snowflake, str)
+
Mapping of user IDs/role IDs to :class:`disco.bot.commands.CommandLevesls` which is used for the default commands_level_getter.
+
+
+
plugins
+
list[string]
+
List of plugin modules to load.
+
+
+
commands_enabled
+
bool
+
Whether this bot instance should utilize command parsing. Generally this should be true, unless your bot is only handling events and has no user interaction.
+
+
+
commands_require_mention
+
bool
+
Whether messages must mention the bot to be considered for command parsing.
+
+
+
commands_mention_rules
+
dict(str, bool)
+
A dictionary describing what mention types can be considered a mention of the bot when using :attr:`commands_require_mention`. This dictionary can contain the following keys: `here`, `everyone`, `role`, `user`. When a keys value is set to true, the mention type will be considered for command parsing.
+
+
+
commands_prefix
+
str
+
A string prefix that is required for a message to be considered for command parsing.
+
+
+
commands_allow_edit
+
bool
+
If true, the bot will reparse an edited message if it was the last sent message in a channel, and did not previously trigger a command. This is helpful for allowing edits to typod commands.
+
+
+
commands_level_getter
+
function
+
If set, a function which when given a GuildMember or User, returns the relevant :class:`disco.bot.commands.CommandLevels`.
+
+
+
commands_group_abbrev
+
function
+
If true, command groups may be abbreviated to the least common variation. E.g. the grouping 'test' may be abbreviated down to 't', unless 'tag' exists, in which case it may be abbreviated down to 'te'.
+
+
+
plugin_config_provider
+
Optional[function]
+
If set, this function will replace the default configuration loading function, which normally attempts to load a file located at config/plugin_name.fmt where fmt is the plugin_config_format. The function here should return a valid configuration object which the plugin understands.
+
+
+
plugin_config_format
+
str
+
The serialization format plugin configuration files are in.
+
+
+
plugin_config_dir
+
str
+
The directory plugin configuration is located within.
+
+
+
http_enabled
+
bool
+
Whether to enable the built-in Flask server which allows plugins to handle and route HTTP requests.
+
+
+
http_host
+
str
+
The host string for the HTTP Flask server (if enabled)
+
+
+
http_port
+
int
+
The port for the HTTP Flask server (if enabled)
+
+
+
+
Bot
+
Inherits From LoggingClass
+
Disco's implementation of a simple but extendable Discord bot. Bots consist
+of a set of plugins, and a Disco client.
+
Parameters
+
+
+
+
Name
+
Type
+
Description
+
+
+
+
+
client
+
:class:`disco.client.Client`
+
The client this bot should utilize for its connection.
+
+
+
config
+
Optional[:class:`BotConfig`]
+
The configuration to use for this bot. If not provided will use the defaults inside of :class:`BotConfig`.
+
+
+
+
Attributes
+
+
+
+
Name
+
Type
+
Description
+
+
+
+
+
client
+
`disco.client.Client`
+
The client instance for this bot.
+
+
+
config
+
`BotConfig`
+
The bot configuration instance for this bot.
+
+
+
plugins
+
dict(str, :class:`disco.bot.plugin.Plugin`)
+
Any plugins this bot has loaded
+
+
+
+
Functions
+
init(self, client, config)
+
from_cli(cls,*plugins)
+
Creates a new instance of the bot using the utilities inside of the
+:mod:disco.cli module. Allows passing in a set of uninitialized
+plugin classes to load.
+
Parameters
+
+
+
+
Name
+
Type
+
Description
+
+
+
+
+
plugins
+
Optional[list(:class:`disco.bot.plugin.Plugin`)]
+
Any plugins to load after creating the new bot instance
+
+
+
+
commands(self)
+
Generator of all commands this bots plugins have defined.
+
recompute(self)
+
Called when a plugin is loaded/unloaded to recompute internal state.
+
compute_group_abbrev(self, groups)
+
Computes all possible abbreviations for a command grouping.
+
compute_command_matches_re(self)
+
Computes a single regex which matches all possible command combinations.
An event which is created when a command is triggered. Contains information
+about the message, command, and parsed arguments (along with shortcuts to
+message information).
+
Attributes
+
+
+
+
Name
+
Type
+
Description
+
+
+
+
+
command
+
:class:`Command`
+
The command this event was created for (aka the triggered command).
+
+
+
msg
+
:class:`disco.types.message.Message`
+
The message object which triggered this command.
+
+
+
match
+
:class:`re.MatchObject`
+
The regex match object for the command.
+
+
+
name
+
str
+
The command name (or alias) which was triggered by the command
+
+
+
args
+
list(str)
+
Arguments passed to the command
+
+
+
+
Functions
+
init(self, command, msg, match)
+
codeblock(self)
+
member(self)
+
Guild member (if relevant) for the user that created the message.
+
channel(self)
+
Channel the message was created in.
+
guild(self)
+
Guild (if relevant) the message was created in.
+
author(self)
+
Author of the message.
+
CommandError
+
Inherits From Exception
+
An exception which is thrown when the arguments for a command are invalid,
+or don't match the command's specifications.
+
Functions
+
init(self, msg)
+
Command
+
An object which defines and handles the triggering of a function based on
+user input (aka a command).
+
Attributes
+
+
+
+
Name
+
Type
+
Description
+
+
+
+
+
plugin
+
:class:`disco.bot.plugin.Plugin`
+
The plugin this command is a member of.
+
+
+
func
+
function
+
The function which is called when this command is triggered.
+
+
+
trigger
+
str
+
The primary trigger (aka name).
+
+
+
args
+
Optional[str]
+
The argument format specification.
+
+
+
aliases
+
Optional[list(str)]
+
List of trigger aliases.
+
+
+
group
+
Optional[str]
+
The group this command is a member of.
+
+
+
is_regex
+
Optional[bool]
+
Whether the triggers for this command should be treated as raw regex.
Discord authentication token, can be validated using the `disco.util.token.is_valid_token` function.
+
+
+
shard_id
+
int
+
The shard ID for the current client instance.
+
+
+
shard_count
+
int
+
The total count of shards running.
+
+
+
max_reconnects
+
int
+
The maximum number of connection retries to make before giving up (0 = never give up). log_level: str The logging level to use.
+
+
+
manhole_enable
+
bool
+
Whether to enable the manhole (e.g. console backdoor server) utility.
+
+
+
manhole_bind
+
tuple(str, int)
+
A (host, port) combination which the manhole server will bind to (if its enabled using :attr:`manhole_enable`).
+
+
+
encoder
+
str
+
The type of encoding to use for encoding/decoding data from websockets, should be either 'json' or 'etf'.
+
+
+
+
Client
+
Inherits From LoggingClass
+
Class representing the base entry point that should be used in almost all
+implementation cases. This class wraps the functionality of both the REST API
+(disco.api.client.APIClient) and the realtime gateway API
+
Parameters
+
+
+
+
Name
+
Type
+
Description
+
+
+
+
+
config
+
`ClientConfig`
+
Configuration for this client instance.
+
+
+
+
Attributes
+
+
+
+
Name
+
Type
+
Description
+
+
+
+
+
config
+
`ClientConfig`
+
The runtime configuration for this client.
+
+
+
events
+
`Emitter`
+
An emitter which emits Gateway events.
+
+
+
packets
+
`Emitter`
+
An emitter which emits Gateway packets.
+
+
+
state
+
`State`
+
The state tracking object.
+
+
+
api
+
`APIClient`
+
The API client.
+
+
+
gw
+
`GatewayClient`
+
The gateway client.
+
+
+
manhole_locals
+
dict
+
Dictionary of local variables for each manhole connection. This can be modified to add/modify local variables.
+
+
+
manhole
+
Optional[`BackdoorServer`]
+
Gevent backdoor server (if the manhole is enabled).
Inherits From {'type': 'attribute', 'name': 'with_metaclass', 'value': 'six'}
+
The GatewayEvent class wraps various functionality for events passed to us
+over the gateway websocket, and serves as a simple proxy to inner values for
+some wrapped event-types (e.g. MessageCreate only contains a message, so we
+proxy all attributes to the inner message object).
+
Functions
+
from_dispatch(client, data)
+
Create a new GatewayEvent instance based on event data.
+
create(cls, obj, client)
+
Create this GatewayEvent class from data and the client.
+
getattr(self, name)
+
Ready
+
Inherits From GatewayEvent
+
Sent after the initial gateway handshake is complete. Contains data required
+for bootstrapping the client's states.
+
Attributes
+
+
+
+
Name
+
Type
+
Description
+
+
+
+
+
version
+
int
+
The gateway version.
+
+
+
session_id
+
str
+
The session ID.
+
+
+
user
+
:class:`disco.types.user.User`
+
The user object for the authed account.
+
+
+
guilds
+
list[:class:`disco.types.guild.Guild`
+
All guilds this account is a member of. These are shallow guild objects. private_channels list[:class:`disco.types.channel.Channel`] All private channels (DMs) open for this account.
+
+
+
+
Resumed
+
Inherits From GatewayEvent
+
Sent after a resume completes.
+
GuildCreate
+
Inherits From GatewayEvent
+
Sent when a guild is joined, or becomes available.
+
Attributes
+
+
+
+
Name
+
Type
+
Description
+
+
+
+
+
guild
+
:class:`disco.types.guild.Guild`
+
The guild being created (e.g. joined)
+
+
+
unavailable
+
bool
+
If false, this guild is coming online from a previously unavailable state, and if None, this is a normal guild join event.
+
+
+
+
Functions
+
created(self)
+
Shortcut property which is true when we actually joined the guild.
+
GuildUpdate
+
Inherits From GatewayEvent
+
Sent when a guild is updated.
+
Attributes
+
+
+
+
Name
+
Type
+
Description
+
+
+
+
+
guild
+
:class:`disco.types.guild.Guild`
+
The updated guild object.
+
+
+
+
GuildDelete
+
Inherits From GatewayEvent
+
Sent when a guild is deleted, left, or becomes unavailable.
+
Attributes
+
+
+
+
Name
+
Type
+
Description
+
+
+
+
+
id
+
snowflake
+
The ID of the guild being deleted.
+
+
+
unavailable
+
bool
+
If true, this guild is becoming unavailable, if None this is a normal guild leave event.
+
+
+
+
Functions
+
deleted(self)
+
Shortcut property which is true when we actually have left the guild.
+
ChannelCreate
+
Inherits From GatewayEvent
+
Sent when a channel is created.
+
Attributes
+
+
+
+
Name
+
Type
+
Description
+
+
+
+
+
channel
+
:class:`disco.types.channel.Channel`
+
The channel which was created.
+
+
+
+
ChannelUpdate
+
Inherits From ChannelCreate
+
Sent when a channel is updated.
+
Attributes
+
+
+
+
Name
+
Type
+
Description
+
+
+
+
+
channel
+
:class:`disco.types.channel.Channel`
+
The channel which was updated.
+
+
+
+
ChannelDelete
+
Inherits From ChannelCreate
+
Sent when a channel is deleted.
+
Attributes
+
+
+
+
Name
+
Type
+
Description
+
+
+
+
+
channel
+
:class:`disco.types.channel.Channel`
+
The channel being deleted.
+
+
+
+
ChannelPinsUpdate
+
Inherits From GatewayEvent
+
Sent when a channel's pins are updated.
+
Attributes
+
+
+
+
Name
+
Type
+
Description
+
+
+
+
+
channel_id
+
snowflake
+
ID of the channel where pins where updated.
+
+
+
last_pin_timestap
+
datetime
+
The time the last message was pinned.
+
+
+
+
GuildBanAdd
+
Inherits From GatewayEvent
+
Sent when a user is banned from a guild.
+
Attributes
+
+
+
+
Name
+
Type
+
Description
+
+
+
+
+
guild_id
+
snowflake
+
The ID of the guild the user is being banned from.
+
+
+
user
+
:class:`disco.types.user.User`
+
The user being banned from the guild.
+
+
+
+
Functions
+
guild(self)
+
GuildBanRemove
+
Inherits From GuildBanAdd
+
Sent when a user is unbanned from a guild.
+
Attributes
+
+
+
+
Name
+
Type
+
Description
+
+
+
+
+
guild_id
+
snowflake
+
The ID of the guild the user is being unbanned from.
+
+
+
user
+
:class:`disco.types.user.User`
+
The user being unbanned from the guild.
+
+
+
+
Functions
+
guild(self)
+
GuildEmojisUpdate
+
Inherits From GatewayEvent
+
Sent when a guild's emojis are updated.
+
Attributes
+
+
+
+
Name
+
Type
+
Description
+
+
+
+
+
guild_id
+
snowflake
+
The ID of the guild the emojis are being updated in.
+
+
+
emojis
+
list[:class:`disco.types.guild.Emoji`]
+
The new set of emojis for the guild
+
+
+
+
GuildIntegrationsUpdate
+
Inherits From GatewayEvent
+
Sent when a guild's integrations are updated.
+
Attributes
+
+
+
+
Name
+
Type
+
Description
+
+
+
+
+
guild_id
+
snowflake
+
The ID of the guild integrations where updated in.
+
+
+
+
GuildMembersChunk
+
Inherits From GatewayEvent
+
Sent in response to a member's chunk request.
+
Attributes
+
+
+
+
Name
+
Type
+
Description
+
+
+
+
+
guild_id
+
snowflake
+
The ID of the guild this member chunk is for.
+
+
+
members
+
list[:class:`disco.types.guild.GuildMember`]
+
The chunk of members.
+
+
+
+
Functions
+
guild(self)
+
GuildMemberAdd
+
Inherits From GatewayEvent
+
Sent when a user joins a guild.
+
Attributes
+
+
+
+
Name
+
Type
+
Description
+
+
+
+
+
member
+
:class:`disco.types.guild.GuildMember`
+
The member that has joined the guild.
+
+
+
+
GuildMemberRemove
+
Inherits From GatewayEvent
+
Sent when a user leaves a guild (via leaving, kicking, or banning).
+
Attributes
+
+
+
+
Name
+
Type
+
Description
+
+
+
+
+
guild_id
+
snowflake
+
The ID of the guild the member left from.
+
+
+
user
+
:class:`disco.types.user.User`
+
The user who was removed from the guild.
+
+
+
+
Functions
+
guild(self)
+
GuildMemberUpdate
+
Inherits From GatewayEvent
+
Sent when a guilds member is updated.
+
Attributes
+
+
+
+
Name
+
Type
+
Description
+
+
+
+
+
member
+
:class:`disco.types.guild.GuildMember`
+
The member being updated
+
+
+
+
GuildRoleCreate
+
Inherits From GatewayEvent
+
Sent when a role is created.
+
Attributes
+
+
+
+
Name
+
Type
+
Description
+
+
+
+
+
guild_id
+
snowflake
+
The ID of the guild where the role was created.
+
+
+
role
+
:class:`disco.types.guild.Role`
+
The role that was created.
+
+
+
+
Functions
+
guild(self)
+
GuildRoleUpdate
+
Inherits From GuildRoleCreate
+
Sent when a role is updated.
+
Attributes
+
+
+
+
Name
+
Type
+
Description
+
+
+
+
+
guild_id
+
snowflake
+
The ID of the guild where the role was created.
+
+
+
role
+
:class:`disco.types.guild.Role`
+
The role that was created.
+
+
+
+
Functions
+
guild(self)
+
GuildRoleDelete
+
Inherits From GatewayEvent
+
Sent when a role is deleted.
+
Attributes
+
+
+
+
Name
+
Type
+
Description
+
+
+
+
+
guild_id
+
snowflake
+
The ID of the guild where the role is being deleted.
+
+
+
role_id
+
snowflake
+
The id of the role being deleted.
+
+
+
+
Functions
+
guild(self)
+
MessageCreate
+
Inherits From GatewayEvent
+
Sent when a message is created.
+
Attributes
+
+
+
+
Name
+
Type
+
Description
+
+
+
+
+
message
+
:class:`disco.types.message.Message`
+
The message being created.
+
+
+
+
MessageUpdate
+
Inherits From MessageCreate
+
Sent when a message is updated/edited.
+
Attributes
+
+
+
+
Name
+
Type
+
Description
+
+
+
+
+
message
+
:class:`disco.types.message.Message`
+
The message being updated.
+
+
+
+
MessageDelete
+
Inherits From GatewayEvent
+
Sent when a message is deleted.
+
Attributes
+
+
+
+
Name
+
Type
+
Description
+
+
+
+
+
id
+
snowflake
+
The ID of message being deleted.
+
+
+
channel_id
+
snowflake
+
The ID of the channel the message was deleted in.
+
+
+
+
Functions
+
channel(self)
+
guild(self)
+
MessageDeleteBulk
+
Inherits From GatewayEvent
+
Sent when multiple messages are deleted from a channel.
+
Attributes
+
+
+
+
Name
+
Type
+
Description
+
+
+
+
+
channel_id
+
snowflake
+
The channel the messages are being deleted in.
+
+
+
ids
+
list[snowflake]
+
List of messages being deleted in the channel.
+
+
+
+
Functions
+
channel(self)
+
guild(self)
+
PresenceUpdate
+
Inherits From GatewayEvent
+
Sent when a user's presence is updated.
+
Attributes
+
+
+
+
Name
+
Type
+
Description
+
+
+
+
+
presence
+
:class:`disco.types.user.Presence`
+
The updated presence object.
+
+
+
guild_id
+
snowflake
+
The guild this presence update is for.
+
+
+
roles
+
list[snowflake]
+
List of roles the user from the presence is part of.
+
+
+
+
Functions
+
guild(self)
+
TypingStart
+
Inherits From GatewayEvent
+
Sent when a user begins typing in a channel.
+
Attributes
+
+
+
+
Name
+
Type
+
Description
+
+
+
+
+
channel_id
+
snowflake
+
The ID of the channel where the user is typing.
+
+
+
user_id
+
snowflake
+
The ID of the user who is typing.
+
+
+
timestamp
+
datetime
+
When the user started typing.
+
+
+
+
VoiceStateUpdate
+
Inherits From GatewayEvent
+
Sent when a users voice state changes.
+
Attributes
+
+
+
+
Name
+
Type
+
Description
+
+
+
+
+
state
+
:class:`disco.models.voice.VoiceState`
+
The voice state which was updated.
+
+
+
+
VoiceServerUpdate
+
Inherits From GatewayEvent
+
Sent when a voice server is updated.
+
Attributes
+
+
+
+
Name
+
Type
+
Description
+
+
+
+
+
token
+
str
+
The token for the voice server.
+
+
+
endpoint
+
str
+
The endpoint for the voice server.
+
+
+
guild_id
+
snowflake
+
The guild ID this voice server update is for.
+
+
+
+
WebhooksUpdate
+
Inherits From GatewayEvent
+
Sent when a channels webhooks are updated.
+
Attributes
+
+
+
+
Name
+
Type
+
Description
+
+
+
+
+
channel_id
+
snowflake
+
The channel ID this webhooks update is for.
+
+
+
guild_id
+
snowflake
+
The guild ID this webhooks update is for.
+
+
+
+
MessageReactionAdd
+
Inherits From GatewayEvent
+
Sent when a reaction is added to a message.
+
Attributes
+
+
+
+
Name
+
Type
+
Description
+
+
+
+
+
channel_id
+
snowflake
+
The channel ID the message is in.
+
+
+
messsage_id
+
snowflake
+
The ID of the message for which the reaction was added too.
+
+
+
user_id
+
snowflake
+
The ID of the user who added the reaction.
+
+
+
emoji
+
:class:`disco.types.message.MessageReactionEmoji`
+
The emoji which was added.
+
+
+
+
Functions
+
delete(self)
+
channel(self)
+
guild(self)
+
MessageReactionRemove
+
Inherits From GatewayEvent
+
Sent when a reaction is removed from a message.
+
Attributes
+
+
+
+
Name
+
Type
+
Description
+
+
+
+
+
channel_id
+
snowflake
+
The channel ID the message is in.
+
+
+
messsage_id
+
snowflake
+
The ID of the message for which the reaction was removed from.
+
+
+
user_id
+
snowflake
+
The ID of the user who originally added the reaction.
+
+
+
emoji
+
:class:`disco.types.message.MessageReactionEmoji`
+
The emoji which was removed.
+
+
+
+
Functions
+
channel(self)
+
guild(self)
+
MessageReactionRemoveAll
+
Inherits From GatewayEvent
+
Sent when all reactions are removed from a message.
+
Attributes
+
+
+
+
Name
+
Type
+
Description
+
+
+
+
+
channel_id
+
snowflake
+
The channel ID the message is in.
+
+
+
message_id
+
snowflake
+
The ID of the message for which the reactions where removed from.
A message stored on a stack inside of the state object, used for tracking
+previously sent messages in channels.
+
Attributes
+
+
+
+
Name
+
Type
+
Description
+
+
+
+
+
id
+
snowflake
+
the id of the message
+
+
+
channel_id
+
snowflake
+
the id of the channel this message was sent in
+
+
+
author_id
+
snowflake
+
the id of the author of this message
+
+
+
+
StateConfig
+
Inherits From Config
+
A configuration object for determining how the State tracking behaves.
+
Attributes
+
+
+
+
Name
+
Type
+
Description
+
+
+
+
+
track_messages
+
bool
+
Whether the state store should keep a buffer of previously sent messages. Message tracking allows for multiple higher-level shortcuts and can be highly useful when developing bots that need to delete their own messages. Message tracking is implemented using a deque and a namedtuple, meaning it should generally not have a high impact on memory, however users who find they do not need and may be experiencing memory pressure can disable this feature entirely using this attribute.
+
+
+
track_messages_size
+
int
+
The size of the messages deque for each channel. This value can be used to calculate the total number of possible `StackMessage` objects kept in memory, simply: `total_messages_size * total_channels`. This value can be tweaked based on usage and to help prevent memory pressure.
+
+
+
sync_guild_members
+
bool
+
If true, guilds will be automatically synced when they are initially loaded or joined. Generally this setting is OK for smaller bots, however bots in over 50 guilds will notice this operation can take a while to complete.
+
+
+
+
State
+
The State class is used to track global state based on events emitted from
+the GatewayClient. State tracking is a core component of the Disco client,
+providing the mechanism for most of the higher-level utility functions.
+
Attributes
+
+
+
+
Name
+
Type
+
Description
+
+
+
+
+
EVENTS
+
list(str)
+
A list of all events the State object binds to
+
+
+
client
+
`disco.client.Client`
+
The Client instance this state is attached to
+
+
+
config
+
`StateConfig`
+
The configuration for this state instance
+
+
+
me
+
`User`
+
The currently logged in user
+
+
+
dms
+
dict(snowflake, `Channel`)
+
Mapping of all known DM Channels
+
+
+
guilds
+
dict(snowflake, `Guild`)
+
Mapping of all known/loaded Guilds
+
+
+
channels
+
dict(snowflake, `Channel`)
+
Weak mapping of all known/loaded Channels
+
+
+
users
+
dict(snowflake, `User`)
+
Weak mapping of all known/loaded Users
+
+
+
voice_states
+
dict(str, `VoiceState`)
+
Weak mapping of all known/active Voice States
+
+
+
messages
+
Optional[dict(snowflake, deque)]
+
Mapping of channel ids to deques containing `StackMessage` objects
+
+
+
+
Functions
+
init(self, client, config)
+
unbind(self)
+
Unbinds all bound event listeners for this state object.
+
bind(self)
+
Binds all events for this state object, storing the listeners for later
Whether this channel is a DM (does not belong to a guild).
+
is_nsfw(self)
+
Whether this channel is an NSFW channel.
+
is_voice(self)
+
Whether this channel supports voice.
+
messages(self)
+
A default MessageIterator for the channel, can be used to quickly and
+easily iterate over the channels entire message history. For more control,
+use Channel.messages_iter.
+
guild(self)
+
Guild this channel belongs to (or None if not applicable).
+
parent(self)
+
Parent this channel belongs to (or None if not applicable).
+
messages_iter(self,**kwargs)
+
Creates a new MessageIterator for the channel with the given keyword
+
get_message(self, message)
+
Attempts to fetch and return a Message from the message object
+or id.
+
Returns
+
The fetched message
+
get_invites(self)
+
Returns
+
Returns a list of all invites for this channel.
+
create_invite(self,*args,**kwargs)
+
Attempts to create a new invite with the given arguments. For more
+information see Invite.create_for_channel.
+
Returns
+
get_pins(self)
+
Returns
+
Returns a list of all pinned messages for this channel.
+
create_pin(self, message)
+
Pins the given message to the channel.
+
Params
+
+
+
+
Name
+
Type
+
Description
+
+
+
+
+
message
+
`Message`|snowflake
+
The message or message ID to pin.
+
+
+
+
delete_pin(self, message)
+
Unpins the given message from the channel.
+
Params
+
+
+
+
Name
+
Type
+
Description
+
+
+
+
+
message
+
`Message`|snowflake
+
The message or message ID to pin.
+
+
+
+
get_webhooks(self)
+
Returns
+
Returns a list of all webhooks for this channel.
+
create_webhook(self,*args,**kwargs)
+
Creates a webhook for this channel. See APIClient.channels_webhooks_create
+for more information.
+
Returns
+
The created webhook.
+
send_message(self,*args,**kwargs)
+
Send a message to this channel. See APIClient.channels_messages_create
+for more information.
+
Returns
+
The created message.
+
connect(self,*args,**kwargs)
+
Connect to this channel over voice.
+
create_overwrite(self,*args,**kwargs)
+
Creates a PermissionOverwrite for this channel. See
+PermissionOverwrite.create_for_channel for more information.
+
delete_message(self, message)
+
Deletes a single message from this channel.
+
Args
+
+
+
+
Name
+
Type
+
Description
+
+
+
+
+
message
+
snowflake|`Message`
+
The message to delete.
+
+
+
+
delete_messages(self, messages)
+
Deletes a set of messages using the correct API route based on the number
+of messages passed.
+
Args
+
+
+
+
Name
+
Type
+
Description
+
+
+
+
+
messages
+
list(snowflake|`Message`)
+
List of messages (or message ids) to delete. All messages must originate from this channel.
+
+
+
+
delete(self,**kwargs)
+
close(self)
+
Closes a DM channel. This is intended as a safer version of delete,
+enforcing that the channel is actually a DM.
+
set_topic(self, topic, reason)
+
Sets the channels topic.
+
set_name(self, name, reason)
+
Sets the channels name.
+
set_position(self, position, reason)
+
Sets the channels position.
+
set_nsfw(self, value, reason)
+
Sets whether the channel is NSFW.
+
set_bitrate(self, bitrate, reason)
+
Sets the channels bitrate.
+
set_user_limit(self, user_limit, reason)
+
Sets the channels user limit.
+
set_parent(self, parent, reason)
+
Sets the channels parent.
+
create_text_channel(self,*args,**kwargs)
+
Creates a sub-text-channel in this category. See Guild.create_text_channel
+for arguments and more information.
+
create_voice_channel(self,*args,**kwargs)
+
Creates a sub-voice-channel in this category. See Guild.create_voice_channel
+for arguments and more information.
+
MessageIterator
+
An iterator which supports scanning through the messages for a channel.
+
Parameters
+
+
+
+
Name
+
Type
+
Description
+
+
+
+
+
client
+
:class:`disco.client.Client`
+
The disco client instance to use when making requests.
+
+
+
channel
+
`Channel`
+
The channel to iterate within.
+
+
+
direction
+
:attr:`MessageIterator.Direction`
+
The direction in which this iterator will move.
+
+
+
bulk
+
bool
+
If true, this iterator will yield messages in list batches, otherwise each message will be yield individually.
A utility class which wraps the functionality of :class:websocket.WebSocketApp
+changing its behavior to better conform with standard style across disco.
+
The major difference comes with the move from callback functions, to all
+events being piped into a single emitter.
Commands are a big part of the Discord bot usage. A command can be defined as an order you give to a bot. Basic examples of commands are:
+!help or !info, most bots have either of the two.
+In the case of these examples, when you send !help or !info the bot will reply with a help or info message.
+
Basic commands
+
Creating commands in Disco is really easy because of the Plugins that are a core fundamential of Disco. For more info on them, read back in the Plugins section of this tutorial. Creating a basic command is done as follows:
+First, create a Plugin class:
+
classmyPlugin(Plugin):
+
+
Now, we can add a command to it. The command will be named ping, and it will simply reply with pong!
What we did here, was add an argument to our command. The argument we created here, content, is required. This means the command won't work if you don't pass in data for the content argument.
+You can also add optional arguments to a command. Instead of surrounding the name and type in angle brackets, you'd surround them in square brackets like this: [content:str...]
+Keep in mind that arguments that are optional might not be there. You'll have to create some checks so that your program doesn't crash on unexpected null values.
+
Command groups
+
Now that we have 2 basic commands and we know to create basic commands and add some arguments to it. Let's create a more advanced command utilizing what we just learned.
+The command will take 2 numbers (integers) and simply adds them together. It will work like this: !math add 1 4 and it would return 5. Instead of passing 'math add' as the command name, we'll be using command groups here.
+Using command groups you can easily group commands together and create sub commands. Now, here comes our math command:
+
@Plugin.command('add','<a:int> <b:int>', group='math')
+defon_add_command(self, event, a, b):
+ event.msg.reply('{}'.format(a+b))
+
+
Here, we added multiple arguments to our command. Namely, number a and number b, that we add together and return back. Of course, you can do loads more fun things with the Disco command handler.
+
Optional arguments
+
Lets create a tag system, that can either store a tag if you'd use it like this: !tag name value or retrieve a tag if you'd use it like this: !tag name
+
We'll need 2 arguments. A name argument that's required, and an optional value argument. Inside the command we'll check if a value is provided. If there is, we'll store the tag. Otherwise, we'll try to retrieve the previously set value for that tag and return it.
+For the sake of this example, we'll asume that the tags dict gets stored somewhere so it doesn't get removed after a restart.
+
tags ={}
+
+@Plugin.command('tag','<name:str> [value:str...]')
+defon_tag_command(self, event, name, value=None):
+
+ if value:
+ tags[name]= value
+ event.msg.reply(':ok_hand: created tag `{}`'.format(name))
+ else:
+ if name in tags.keys():
+ return event.msg.reply(tags[name])
+ else:
+ return event.msg.reply('Unknown tag: `{}`'.format(name))
+
+
ArgumentParser
+
A different way of adding arguments to a command is by using argparse.ArgumentParser. With argparser it's easier to create more complicated commands with many options or flags.
+Let's put this into practice by recreating our math add command, but using argparser. More info on argparser and the add_argument() method can be found here
Listeners are a way to execute custom actions when a certain Discord event happens. For example, on message creation, when a member joins or leaves a guild, or when someone changes their username or nickname.
+
Listeners in disco
+
Listeners are easy to use and implement in Disco. First of all, we'll create a Plugin like so:
+
classMyPlugin(Plugin):
+
+
Now, inside this plugin, we'll create our first listener. A listener is built up following this syntax:
+
@Plugin.listen('EventName')
+defon_event_name(self, event):
+ # Do something with the event
+
+
Change the 'EventName' in the .listen() method to the event name you want to listen to, and give the on_event_name method a more descriptive name.
+
This listener will listen for a new message and will reply with the exact same message every time.
Let's create another listener, this time one that listens for a member that's added to the guild, when this happens, it will send a welcome message in a welcome channel:
+
WELCOME_CHANNEL =381890676654080001
+
+@Plugin.listen('GuildMemberAdd')
+defon_member_add(self, event):
+ self.bot.client.state.channels.get(WELCOME_CHANNEL).send_message(
+ 'Welcome to the server {}'.format(event.member.user.mention())
+ )
+
+
A list of all Discord events supported by disco can be found here including event attributes and functions you can use on the event property.
+
These are all the listeners we created in this tutorial:
+
classMyPlugin(Plugin):
+ @Plugin.listen('MesageCreate')
+ defon_message_create(self, event):
+ event.reply(event.message.content)
+
+ WELCOME_CHANNEL =381890676654080001
+
+ @Plugin.listen('GuildMemberAdd')
+ defon_member_add(self, event):
+ self.bot.client.state.channels.get(WELCOME_CHANNEL).send_message(
+ 'Welcome to the server {}'.format(event.member.user.mention())
+ )
+
Plugins are Disco are a core abstraction which attempt to encapsulate the functionality of your bot into contained modules. To boil it down, commands related to one another, or listeners that control the same functionality should be within the same Plugin. Although it's possible to call and pass data between Plugins, you should generally attempt to avoid it.
+
Plugin Lifecycle
+
Loading
+
Plugins are loaded when the Bot is initially created, and when this happens the Plugin.load function is called. If the plugin is being reloaded, the call to this function will contain a dictionary of data returned by the previous unload call. Using this, you can pass data between loaded instances of your plugin to help aid in seamless reloads. Often plugins will require some level of configuration and setup before running, and this code can be inserted within an overridden version of the load function, as such:
The load function of a plugin is guaranteed to only be called once for the instance, when reloading a new instance of the plugin will be created.
+
Unloading
+
Plugins are unloaded in multiple scenarios (shutdown, before a reload, or during an unload), and when this happens the Plugin.unload function is called. This function is passed one argument containing a dictionary, which (if the plugin wants) can be filled with information that a future iteration (in the case we're reloading) of the plugin can use to maintain state. Plugins may want to call or save data before being unloaded, and in this case they can override the unload function:
During the unload sequence all greenlets which the plugin owns (e.g. greenlets for command or listener callbacks, any spawned with Plugin.spawn) are terminated. In the case where command callbacks should continue execution past the unload point (e.g. in the case where a plugin reloads itself), you should pass oob=True to the Plugin.command decorator.
+
Configuration
+
Disco supports a framework for dynamically passing configuration to plugins. By default, configuration files live within the config/ directory, and are named after the plugin, e.g. ExamplePlugin would be configured via config/example.json. Adding support for configuration within your plugin can be done via a decorator:
Disco provides a built-in set of tools for building and running Discord bots which can be used to quickly and easily create integrations. Within this tutorial you'll be shown how to install Disco, write plugins, and run bots. This tutorial assumes you've already followed the Installation Steps.
+
Creating a Bot
+
The first step to creating bots is to actually register them on Discord itself. To do this, you'll need to be logged into your Discord account on the browser and then navigate to My Apps. Here you'll have the option to create a new application, and once created you can add a bot user (by clicking "Create a Bot User") to your application. Finally, you'll want to keep track of the bot user token which can be shown by clicking the "click to reveal" link next to the token field.
+
Once you have a Discord bot account, you can then setup your workspace. For now we'll just need a folder (perhaps called disco-tutorial) with a few files in it:
The __init__.py file is required for Python to find your plugin, but it can remain empty.
+
+
Now let's setup the configuration file. To start off with we'll paste the following template in and modify our token key (MY_BOT_TOKEN_HERE) to be the token we obtained above. The plugins section tells disco what plugins to load, based on a module path (similar to how Python imports work). In this example we're asking disco to load the plugin contained in the tutorial file within the plugins directory (or "module"). Disco by default loads the first plugin it finds within the module, so you want to make sure each plugin class is contained within its own file.
Now we're ready to write our plugin. Plugins are used to isolate the functionality of your bot into components. Plugins can be dynamically loaded, unloaded and reloaded at runtime. Lets start off by writing a plugin with a "ping" command;
Now that we have a plugin setup and our configuration is ready, we can run and test the bot. We can do this by executing the following command from within our project directory:
+
python -m disco.cli --config config.json
+
+
If all is successful, you can then test your bot by mentioning it with the command, like so:
+
@tutorial#1234 ping
+
At this point, you've achieved the creation and setup of a very simple bot. Now lets work on understanding and working with more Disco features.
A Message Embed represents a Discord Embed object. An Embed object is another component of Discord messages that can be used to present data with special formatting and structure.
+
An example of a message embed:
+
+
An embed can contain the following components:
+
+
Author, including link and avatar
+
Title
+
Description
+
Field(s)
+
Thumbnail image
+
Image
+
Footer, including text and icon
+
Timestamp
+
Color (sets the color of the left sidebar of the embed)
+
+
Creating an embed
+
Creating an embed is simple, and can be done like this:
+
from disco.types.message import MessageEmbed #We need this to create the embed
+from datetime import datetime #We need this to set the timestamp
+
+embed = MessageEmbed()
+
+
This will create a default, empty, Discord Embed object. Now that we have that, let's assign some values to it. First, lets set the author and the title, with a link that leads to this page. This can be done as follows:
+
embed.set_author(name='b1nzy#1337', url='https://b1naryth1ef.github.com/disco', icon_url='http://i.imgur.com/1tjdUId.jpg')
+embed.title ='How to create an embed'
+embed.url ='https://b1naryth1ef.github.io/disco/bot_tutorial/message_embeds.html'#This URL will be hooked up to the title of the embed
+
+
Now, we can add a description and a few fields:
+
embed.add_field(name='Inline field 1', value='Some value for this field', inline=True)
+embed.add_field(name='Inline field 2', value='Another value for another field', inline=True)
+embed.add_field(name='Inline field 3', value='Third value for the third field', inline=True)
+embed.add_field(name='A non-inline field', value='You can only have a max of 3 inline field on 1 line', inline=False)
+embed.description ='This is the general description of the embed, you can use the Discord supported MD in here too, to make it look extra fancy. For example, creating some **bold** or ~~strikethrough~~ text.'
+
+
Last up, let's set a footer, color and add a timestamp:
+
embed.timestamp = datetime.utcnow().isoformat()
+embed.set_footer(text='Disco Message Embeds tutorial')
+embed.color ='10038562'#This can be any color, but I chose a nice dark red tint
+
+
Once your embed is finshed, you can send it using the channel.send_message() message or the event.msg.reply() function.
+With channel.send_message():