Browse Source

Rename Server to Guild everywhere.

pull/447/head
Rapptz 9 years ago
parent
commit
d1d54a468a
  1. 4
      discord/__init__.py
  2. 2
      discord/abc.py
  3. 8
      discord/calls.py
  4. 66
      discord/channel.py
  5. 444
      discord/client.py
  6. 12
      discord/emoji.py
  7. 2
      discord/enums.py
  8. 6
      discord/ext/commands/bot.py
  9. 50
      discord/ext/commands/converter.py
  10. 6
      discord/ext/commands/cooldowns.py
  11. 10
      discord/ext/commands/core.py
  12. 12
      discord/gateway.py
  13. 90
      discord/guild.py
  14. 12
      discord/http.py
  15. 10
      discord/invite.py
  16. 40
      discord/member.py
  17. 32
      discord/message.py
  18. 24
      discord/permissions.py
  19. 20
      discord/role.py
  20. 276
      discord/state.py
  21. 2
      discord/user.py
  22. 20
      discord/utils.py
  23. 12
      discord/voice_client.py
  24. 102
      docs/api.rst

4
discord/__init__.py

@ -22,7 +22,7 @@ from .user import User
from .game import Game from .game import Game
from .emoji import Emoji from .emoji import Emoji
from .channel import * from .channel import *
from .server import Server from .guild import Guild
from .member import Member, VoiceState from .member import Member, VoiceState
from .message import Message from .message import Message
from .errors import * from .errors import *
@ -35,7 +35,7 @@ from .object import Object
from .reaction import Reaction from .reaction import Reaction
from . import utils, opus, compat, abc from . import utils, opus, compat, abc
from .voice_client import VoiceClient from .voice_client import VoiceClient
from .enums import ChannelType, ServerRegion, Status, MessageType, VerificationLevel from .enums import ChannelType, GuildRegion, Status, MessageType, VerificationLevel
from collections import namedtuple from collections import namedtuple
from .embeds import Embed from .embeds import Embed

2
discord/abc.py

@ -107,7 +107,7 @@ class GuildChannel(metaclass=abc.ABCMeta):
return NotImplemented return NotImplemented
mro = C.__mro__ mro = C.__mro__
for attr in ('name', 'server', 'overwrites_for', 'permissions_for', 'mention'): for attr in ('name', 'guild', 'overwrites_for', 'permissions_for', 'mention'):
for base in mro: for base in mro:
if attr in base.__dict__: if attr in base.__dict__:
break break

8
discord/calls.py

@ -26,7 +26,7 @@ DEALINGS IN THE SOFTWARE.
from . import utils from . import utils
import datetime import datetime
from .enums import ServerRegion, try_enum from .enums import GuildRegion, try_enum
from .member import VoiceState from .member import VoiceState
class CallMessage: class CallMessage:
@ -90,8 +90,8 @@ class GroupCall:
Denotes if this group call is unavailable. Denotes if this group call is unavailable.
ringing: List[:class:`User`] ringing: List[:class:`User`]
A list of users that are currently being rung to join the call. A list of users that are currently being rung to join the call.
region: :class:`ServerRegion` region: :class:`GuildRegion`
The server region the group call is being hosted on. The guild region the group call is being hosted on.
""" """
def __init__(self, **kwargs): def __init__(self, **kwargs):
@ -105,7 +105,7 @@ class GroupCall:
self._update(**kwargs) self._update(**kwargs)
def _update(self, **kwargs): def _update(self, **kwargs):
self.region = try_enum(ServerRegion, kwargs.get('region')) self.region = try_enum(GuildRegion, kwargs.get('region'))
lookup = {u.id: u for u in self.call.channel.recipients} lookup = {u.id: u for u in self.call.channel.recipients}
me = self.call.channel.me me = self.call.channel.me
lookup[me.id] = me lookup[me.id] = me

66
discord/channel.py

@ -51,8 +51,8 @@ class CommonGuildChannel(Hashable):
raise InvalidArgument('Channel position cannot be less than 0.') raise InvalidArgument('Channel position cannot be less than 0.')
http = self._state.http http = self._state.http
url = '{0}/{1.server.id}/channels'.format(http.GUILDS, self) url = '{0}/{1.guild.id}/channels'.format(http.GUILDS, self)
channels = [c for c in self.server.channels if isinstance(c, type(self))] channels = [c for c in self.guild.channels if isinstance(c, type(self))]
if position >= len(channels): if position >= len(channels):
raise InvalidArgument('Channel position cannot be greater than {}'.format(len(channels) - 1)) raise InvalidArgument('Channel position cannot be greater than {}'.format(len(channels) - 1))
@ -75,7 +75,7 @@ class CommonGuildChannel(Hashable):
def _fill_overwrites(self, data): def _fill_overwrites(self, data):
self._overwrites = [] self._overwrites = []
everyone_index = 0 everyone_index = 0
everyone_id = self.server.id everyone_id = self.guild.id
for index, overridden in enumerate(data.get('permission_overwrites', [])): for index, overridden in enumerate(data.get('permission_overwrites', [])):
overridden_id = int(overridden.pop('id')) overridden_id = int(overridden.pop('id'))
@ -100,10 +100,10 @@ class CommonGuildChannel(Hashable):
@property @property
def changed_roles(self): def changed_roles(self):
"""Returns a list of :class:`Roles` that have been overridden from """Returns a list of :class:`Roles` that have been overridden from
their default values in the :attr:`Server.roles` attribute.""" their default values in the :attr:`Guild.roles` attribute."""
ret = [] ret = []
for overwrite in filter(lambda o: o.type == 'role', self._overwrites): for overwrite in filter(lambda o: o.type == 'role', self._overwrites):
role = utils.get(self.server.roles, id=overwrite.id) role = utils.get(self.guild.roles, id=overwrite.id)
if role is None: if role is None:
continue continue
@ -114,8 +114,8 @@ class CommonGuildChannel(Hashable):
@property @property
def is_default(self): def is_default(self):
"""bool : Indicates if this is the default channel for the :class:`Server` it belongs to.""" """bool : Indicates if this is the default channel for the :class:`Guild` it belongs to."""
return self.server.id == self.id return self.guild.id == self.id
@property @property
def mention(self): def mention(self):
@ -190,8 +190,8 @@ class CommonGuildChannel(Hashable):
This function takes into consideration the following cases: This function takes into consideration the following cases:
- Server owner - Guild owner
- Server roles - Guild roles
- Channel overrides - Channel overrides
- Member overrides - Member overrides
- Whether the channel is the default channel. - Whether the channel is the default channel.
@ -208,7 +208,7 @@ class CommonGuildChannel(Hashable):
""" """
# The current cases can be explained as: # The current cases can be explained as:
# Server owner get all permissions -- no questions asked. Otherwise... # Guild owner get all permissions -- no questions asked. Otherwise...
# The @everyone role gets the first application. # The @everyone role gets the first application.
# After that, the applied roles that the user has in the channel # After that, the applied roles that the user has in the channel
# (or otherwise) are then OR'd together. # (or otherwise) are then OR'd together.
@ -223,17 +223,17 @@ class CommonGuildChannel(Hashable):
# The operation first takes into consideration the denied # The operation first takes into consideration the denied
# and then the allowed. # and then the allowed.
if member.id == self.server.owner.id: if member.id == self.guild.owner.id:
return Permissions.all() return Permissions.all()
default = self.server.default_role default = self.guild.default_role
base = Permissions(default.permissions.value) base = Permissions(default.permissions.value)
# Apply server roles that the member has. # Apply guild roles that the member has.
for role in member.roles: for role in member.roles:
base.value |= role.permissions.value base.value |= role.permissions.value
# Server-wide Administrator -> True for everything # Guild-wide Administrator -> True for everything
# Bypass all channel-specific overrides # Bypass all channel-specific overrides
if base.administrator: if base.administrator:
return Permissions.all() return Permissions.all()
@ -300,7 +300,7 @@ class CommonGuildChannel(Hashable):
yield from self._state.http.delete_channel(self.id) yield from self._state.http.delete_channel(self.id)
class TextChannel(abc.MessageChannel, CommonGuildChannel): class TextChannel(abc.MessageChannel, CommonGuildChannel):
"""Represents a Discord server text channel. """Represents a Discord guild text channel.
Supported Operations: Supported Operations:
@ -320,8 +320,8 @@ class TextChannel(abc.MessageChannel, CommonGuildChannel):
----------- -----------
name: str name: str
The channel name. The channel name.
server: :class:`Server` guild: :class:`Guild`
The server the channel belongs to. The guild the channel belongs to.
id: int id: int
The channel ID. The channel ID.
topic: Optional[str] topic: Optional[str]
@ -331,23 +331,23 @@ class TextChannel(abc.MessageChannel, CommonGuildChannel):
top channel is position 0. top channel is position 0.
""" """
__slots__ = ( 'name', 'id', 'server', 'topic', '_state', __slots__ = ( 'name', 'id', 'guild', 'topic', '_state',
'position', '_overwrites' ) 'position', '_overwrites' )
def __init__(self, *, state, server, data): def __init__(self, *, state, guild, data):
self._state = state self._state = state
self.id = int(data['id']) self.id = int(data['id'])
self._update(server, data) self._update(guild, data)
def _update(self, server, data): def _update(self, guild, data):
self.server = server self.guild = guild
self.name = data['name'] self.name = data['name']
self.topic = data.get('topic') self.topic = data.get('topic')
self.position = data['position'] self.position = data['position']
self._fill_overwrites(data) self._fill_overwrites(data)
def _get_destination(self): def _get_destination(self):
return self.id, self.server.id return self.id, self.guild.id
@asyncio.coroutine @asyncio.coroutine
def edit(self, **options): def edit(self, **options):
@ -385,10 +385,10 @@ class TextChannel(abc.MessageChannel, CommonGuildChannel):
if options: if options:
data = yield from self._state.http.edit_channel(self.id, **options) data = yield from self._state.http.edit_channel(self.id, **options)
self._update(self.server, data) self._update(self.guild, data)
class VoiceChannel(CommonGuildChannel): class VoiceChannel(CommonGuildChannel):
"""Represents a Discord server voice channel. """Represents a Discord guild voice channel.
Supported Operations: Supported Operations:
@ -408,8 +408,8 @@ class VoiceChannel(CommonGuildChannel):
----------- -----------
name: str name: str
The channel name. The channel name.
server: :class:`Server` guild: :class:`Guild`
The server the channel belongs to. The guild the channel belongs to.
id: int id: int
The channel ID. The channel ID.
position: int position: int
@ -423,17 +423,17 @@ class VoiceChannel(CommonGuildChannel):
The channel's limit for number of members that can be in a voice channel. The channel's limit for number of members that can be in a voice channel.
""" """
__slots__ = ( 'voice_members', 'name', 'id', 'server', 'bitrate', __slots__ = ( 'voice_members', 'name', 'id', 'guild', 'bitrate',
'user_limit', '_state', 'position', '_overwrites' ) 'user_limit', '_state', 'position', '_overwrites' )
def __init__(self, *, state, server, data): def __init__(self, *, state, guild, data):
self._state = state self._state = state
self.id = int(data['id']) self.id = int(data['id'])
self._update(server, data) self._update(guild, data)
self.voice_members = [] self.voice_members = []
def _update(self, server, data): def _update(self, guild, data):
self.server = server self.guild = guild
self.name = data['name'] self.name = data['name']
self.position = data['position'] self.position = data['position']
self.bitrate = data.get('bitrate') self.bitrate = data.get('bitrate')
@ -475,7 +475,7 @@ class VoiceChannel(CommonGuildChannel):
if options: if options:
data = yield from self._state.http.edit_channel(self.id, **options) data = yield from self._state.http.edit_channel(self.id, **options)
self._update(self.server, data) self._update(self.guild, data)
class DMChannel(abc.MessageChannel, Hashable): class DMChannel(abc.MessageChannel, Hashable):
"""Represents a Discord direct message channel. """Represents a Discord direct message channel.

444
discord/client.py

File diff suppressed because it is too large

12
discord/emoji.py

@ -62,16 +62,16 @@ class Emoji(Hashable):
If colons are required to use this emoji in the client (:PJSalt: vs PJSalt). If colons are required to use this emoji in the client (:PJSalt: vs PJSalt).
managed: bool managed: bool
If this emoji is managed by a Twitch integration. If this emoji is managed by a Twitch integration.
server: :class:`Server` guild: :class:`Guild`
The server the emoji belongs to. The guild the emoji belongs to.
roles: List[:class:`Role`] roles: List[:class:`Role`]
A list of :class:`Role` that is allowed to use this emoji. If roles is empty, A list of :class:`Role` that is allowed to use this emoji. If roles is empty,
the emoji is unrestricted. the emoji is unrestricted.
""" """
__slots__ = ('require_colons', 'managed', 'id', 'name', 'roles', 'server', '_state') __slots__ = ('require_colons', 'managed', 'id', 'name', 'roles', 'guild', '_state')
def __init__(self, *, server, state, data): def __init__(self, *, guild, state, data):
self.server = server self.guild = guild
self._state = state self._state = state
self._from_data(data) self._from_data(data)
@ -83,7 +83,7 @@ class Emoji(Hashable):
self.roles = emoji.get('roles', []) self.roles = emoji.get('roles', [])
if self.roles: if self.roles:
roles = set(self.roles) roles = set(self.roles)
self.roles = [role for role in self.server.roles if role.id in roles] self.roles = [role for role in self.guild.roles if role.id in roles]
def _iterator(self): def _iterator(self):
for attr in self.__slots__: for attr in self.__slots__:

2
discord/enums.py

@ -44,7 +44,7 @@ class MessageType(Enum):
channel_icon_change = 5 channel_icon_change = 5
pins_add = 6 pins_add = 6
class ServerRegion(Enum): class GuildRegion(Enum):
us_west = 'us-west' us_west = 'us-west'
us_east = 'us-east' us_east = 'us-east'
us_south = 'us-south' us_south = 'us-south'

6
discord/ext/commands/bot.py

@ -55,9 +55,9 @@ def _get_variable(name):
def when_mentioned(bot, msg): def when_mentioned(bot, msg):
"""A callable that implements a command prefix equivalent """A callable that implements a command prefix equivalent
to being mentioned, e.g. ``@bot ``.""" to being mentioned, e.g. ``@bot ``."""
server = msg.server guild = msg.guild
if server is not None: if guild is not None:
return '{0.me.mention} '.format(server) return '{0.me.mention} '.format(guild)
return '{0.user.mention} '.format(bot) return '{0.user.mention} '.format(bot)
def when_mentioned_or(*prefixes): def when_mentioned_or(*prefixes):

50
discord/ext/commands/converter.py

@ -35,10 +35,10 @@ __all__ = [ 'Converter', 'MemberConverter', 'UserConverter',
'ChannelConverter', 'InviteConverter', 'RoleConverter', 'ChannelConverter', 'InviteConverter', 'RoleConverter',
'GameConverter', 'ColourConverter' ] 'GameConverter', 'ColourConverter' ]
def _get_from_servers(bot, getter, argument): def _get_from_guilds(bot, getter, argument):
result = None result = None
for server in bot.servers: for guild in bot.guilds:
result = getattr(server, getter)(argument) result = getattr(guild, getter)(argument)
if result: if result:
return result return result
return result return result
@ -81,20 +81,20 @@ class MemberConverter(IDConverter):
message = self.ctx.message message = self.ctx.message
bot = self.ctx.bot bot = self.ctx.bot
match = self._get_id_match() or re.match(r'<@!?([0-9]+)>$', self.argument) match = self._get_id_match() or re.match(r'<@!?([0-9]+)>$', self.argument)
server = message.server guild = message.guild
result = None result = None
if match is None: if match is None:
# not a mention... # not a mention...
if server: if guild:
result = server.get_member_named(self.argument) result = guild.get_member_named(self.argument)
else: else:
result = _get_from_servers(bot, 'get_member_named', self.argument) result = _get_from_guilds(bot, 'get_member_named', self.argument)
else: else:
user_id = int(match.group(1)) user_id = int(match.group(1))
if server: if guild:
result = server.get_member(user_id) result = guild.get_member(user_id)
else: else:
result = _get_from_servers(bot, 'get_member', user_id) result = _get_from_guilds(bot, 'get_member', user_id)
if result is None: if result is None:
raise BadArgument('Member "{}" not found'.format(self.argument)) raise BadArgument('Member "{}" not found'.format(self.argument))
@ -110,19 +110,19 @@ class ChannelConverter(IDConverter):
match = self._get_id_match() or re.match(r'<#([0-9]+)>$', self.argument) match = self._get_id_match() or re.match(r'<#([0-9]+)>$', self.argument)
result = None result = None
server = message.server guild = message.guild
if match is None: if match is None:
# not a mention # not a mention
if server: if guild:
result = discord.utils.get(server.channels, name=self.argument) result = discord.utils.get(guild.channels, name=self.argument)
else: else:
result = discord.utils.get(bot.get_all_channels(), name=self.argument) result = discord.utils.get(bot.get_all_channels(), name=self.argument)
else: else:
channel_id = int(match.group(1)) channel_id = int(match.group(1))
if server: if guild:
result = server.get_channel(channel_id) result = guild.get_channel(channel_id)
else: else:
result = _get_from_servers(bot, 'get_channel', channel_id) result = _get_from_guilds(bot, 'get_channel', channel_id)
if result is None: if result is None:
raise BadArgument('Channel "{}" not found.'.format(self.argument)) raise BadArgument('Channel "{}" not found.'.format(self.argument))
@ -146,13 +146,13 @@ class ColourConverter(Converter):
class RoleConverter(IDConverter): class RoleConverter(IDConverter):
def convert(self): def convert(self):
server = self.ctx.message.server guild = self.ctx.message.guild
if not server: if not guild:
raise NoPrivateMessage() raise NoPrivateMessage()
match = self._get_id_match() or re.match(r'<@&([0-9]+)>$', self.argument) match = self._get_id_match() or re.match(r'<@&([0-9]+)>$', self.argument)
params = dict(id=int(match.group(1))) if match else dict(name=self.argument) params = dict(id=int(match.group(1))) if match else dict(name=self.argument)
result = discord.utils.get(server.roles, **params) result = discord.utils.get(guild.roles, **params)
if result is None: if result is None:
raise BadArgument('Role "{}" not found.'.format(self.argument)) raise BadArgument('Role "{}" not found.'.format(self.argument))
return result return result
@ -178,11 +178,11 @@ class EmojiConverter(IDConverter):
match = self._get_id_match() or re.match(r'<:[a-zA-Z0-9]+:([0-9]+)>$', self.argument) match = self._get_id_match() or re.match(r'<:[a-zA-Z0-9]+:([0-9]+)>$', self.argument)
result = None result = None
server = message.server guild = message.guild
if match is None: if match is None:
# Try to get the emoji by name. Try local server first. # Try to get the emoji by name. Try local guild first.
if server: if guild:
result = discord.utils.get(server.emojis, name=self.argument) result = discord.utils.get(guild.emojis, name=self.argument)
if result is None: if result is None:
result = discord.utils.get(bot.get_all_emojis(), name=self.argument) result = discord.utils.get(bot.get_all_emojis(), name=self.argument)
@ -190,8 +190,8 @@ class EmojiConverter(IDConverter):
emoji_id = int(match.group(1)) emoji_id = int(match.group(1))
# Try to look up emoji by id. # Try to look up emoji by id.
if server: if guild:
result = discord.utils.get(server.emojis, id=emoji_id) result = discord.utils.get(guild.emojis, id=emoji_id)
if result is None: if result is None:
result = discord.utils.get(bot.get_all_emojis(), id=emoji_id) result = discord.utils.get(bot.get_all_emojis(), id=emoji_id)

6
discord/ext/commands/cooldowns.py

@ -31,7 +31,7 @@ __all__ = ['BucketType', 'Cooldown', 'CooldownMapping']
class BucketType(enum.Enum): class BucketType(enum.Enum):
default = 0 default = 0
user = 1 user = 1
server = 2 guild = 2
channel = 3 channel = 3
class Cooldown: class Cooldown:
@ -97,8 +97,8 @@ class CooldownMapping:
bucket_type = self._cooldown.type bucket_type = self._cooldown.type
if bucket_type is BucketType.user: if bucket_type is BucketType.user:
return msg.author.id return msg.author.id
elif bucket_type is BucketType.server: elif bucket_type is BucketType.guild:
return getattr(msg.server, 'id', msg.author.id) return getattr(msg.guild, 'id', msg.author.id)
elif bucket_type is BucketType.channel: elif bucket_type is BucketType.channel:
return msg.channel.id return msg.channel.id

10
discord/ext/commands/core.py

@ -847,7 +847,7 @@ def bot_has_role(name):
ch = ctx.message.channel ch = ctx.message.channel
if ch.is_private: if ch.is_private:
return False return False
me = ch.server.me me = ch.guild.me
role = discord.utils.get(me.roles, name=name) role = discord.utils.get(me.roles, name=name)
return role is not None return role is not None
return check(predicate) return check(predicate)
@ -860,7 +860,7 @@ def bot_has_any_role(*names):
ch = ctx.message.channel ch = ctx.message.channel
if ch.is_private: if ch.is_private:
return False return False
me = ch.server.me me = ch.guild.me
getter = functools.partial(discord.utils.get, me.roles) getter = functools.partial(discord.utils.get, me.roles)
return any(getter(name=name) is not None for name in names) return any(getter(name=name) is not None for name in names)
return check(predicate) return check(predicate)
@ -871,7 +871,7 @@ def bot_has_permissions(**perms):
""" """
def predicate(ctx): def predicate(ctx):
ch = ctx.message.channel ch = ctx.message.channel
me = ch.server.me if not ch.is_private else ctx.bot.user me = ch.guild.me if not ch.is_private else ctx.bot.user
permissions = ch.permissions_for(me) permissions = ch.permissions_for(me)
return all(getattr(permissions, perm, None) == value for perm, value in perms.items()) return all(getattr(permissions, perm, None) == value for perm, value in perms.items())
return check(predicate) return check(predicate)
@ -882,13 +882,13 @@ def cooldown(rate, per, type=BucketType.default):
A cooldown allows a command to only be used a specific amount A cooldown allows a command to only be used a specific amount
of times in a specific time frame. These cooldowns can be based of times in a specific time frame. These cooldowns can be based
either on a per-server, per-channel, per-user, or global basis. either on a per-guild, per-channel, per-user, or global basis.
Denoted by the third argument of ``type`` which must be of enum Denoted by the third argument of ``type`` which must be of enum
type ``BucketType`` which could be either: type ``BucketType`` which could be either:
- ``BucketType.default`` for a global basis. - ``BucketType.default`` for a global basis.
- ``BucketType.user`` for a per-user basis. - ``BucketType.user`` for a per-user basis.
- ``BucketType.server`` for a per-server basis. - ``BucketType.guild`` for a per-guild basis.
- ``BucketType.channel`` for a per-channel basis. - ``BucketType.channel`` for a per-channel basis.
If a cooldown is triggered, then :exc:`CommandOnCooldown` is triggered in If a cooldown is triggered, then :exc:`CommandOnCooldown` is triggered in

12
discord/gateway.py

@ -115,15 +115,15 @@ class DiscordWebSocket(websockets.client.WebSocketClientProtocol):
PRESENCE PRESENCE
Send only. Updates your presence. Send only. Updates your presence.
VOICE_STATE VOICE_STATE
Send only. Starts a new connection to a voice server. Send only. Starts a new connection to a voice guild.
VOICE_PING VOICE_PING
Send only. Checks ping time to a voice server, do not use. Send only. Checks ping time to a voice guild, do not use.
RESUME RESUME
Send only. Resumes an existing connection. Send only. Resumes an existing connection.
RECONNECT RECONNECT
Receive only. Tells the client to reconnect to a new gateway. Receive only. Tells the client to reconnect to a new gateway.
REQUEST_MEMBERS REQUEST_MEMBERS
Send only. Asks for the full member list of a server. Send only. Asks for the full member list of a guild.
INVALIDATE_SESSION INVALIDATE_SESSION
Receive only. Tells the client to invalidate the session and IDENTIFY Receive only. Tells the client to invalidate the session and IDENTIFY
again. again.
@ -436,8 +436,8 @@ class DiscordWebSocket(websockets.client.WebSocketClientProtocol):
if status_enum is Status.invisible: if status_enum is Status.invisible:
status_enum = Status.offline status_enum = Status.offline
for server in self._connection.servers: for guild in self._connection.guilds:
me = server.me me = guild.me
if me is None: if me is None:
continue continue
@ -524,7 +524,7 @@ class DiscordVoiceWebSocket(websockets.client.WebSocketClientProtocol):
identify = { identify = {
'op': cls.IDENTIFY, 'op': cls.IDENTIFY,
'd': { 'd': {
'server_id': client.guild_id, 'guild_id': client.guild_id,
'user_id': client.user.id, 'user_id': client.user.id,
'session_id': client.session_id, 'session_id': client.session_id,
'token': client.token 'token': client.token

90
discord/server.py → discord/guild.py

@ -30,88 +30,90 @@ from .member import Member, VoiceState
from .emoji import Emoji from .emoji import Emoji
from .game import Game from .game import Game
from .channel import * from .channel import *
from .enums import ServerRegion, Status, ChannelType, try_enum, VerificationLevel from .enums import GuildRegion, Status, ChannelType, try_enum, VerificationLevel
from .mixins import Hashable from .mixins import Hashable
import copy import copy
class Server(Hashable): class Guild(Hashable):
"""Represents a Discord server. """Represents a Discord guild.
This is referred to as a "server" in the official Discord UI.
Supported Operations: Supported Operations:
+-----------+--------------------------------------+ +-----------+--------------------------------------+
| Operation | Description | | Operation | Description |
+===========+======================================+ +===========+======================================+
| x == y | Checks if two servers are equal. | | x == y | Checks if two guilds are equal. |
+-----------+--------------------------------------+ +-----------+--------------------------------------+
| x != y | Checks if two servers are not equal. | | x != y | Checks if two guilds are not equal. |
+-----------+--------------------------------------+ +-----------+--------------------------------------+
| hash(x) | Returns the server's hash. | | hash(x) | Returns the guild's hash. |
+-----------+--------------------------------------+ +-----------+--------------------------------------+
| str(x) | Returns the server's name. | | str(x) | Returns the guild's name. |
+-----------+--------------------------------------+ +-----------+--------------------------------------+
Attributes Attributes
---------- ----------
name: str name: str
The server name. The guild name.
me: :class:`Member` me: :class:`Member`
Similar to :attr:`Client.user` except an instance of :class:`Member`. Similar to :attr:`Client.user` except an instance of :class:`Member`.
This is essentially used to get the member version of yourself. This is essentially used to get the member version of yourself.
roles roles
A list of :class:`Role` that the server has available. A list of :class:`Role` that the guild has available.
emojis emojis
A list of :class:`Emoji` that the server owns. A list of :class:`Emoji` that the guild owns.
region: :class:`ServerRegion` region: :class:`GuildRegion`
The region the server belongs on. There is a chance that the region The region the guild belongs on. There is a chance that the region
will be a ``str`` if the value is not recognised by the enumerator. will be a ``str`` if the value is not recognised by the enumerator.
afk_timeout: int afk_timeout: int
The timeout to get sent to the AFK channel. The timeout to get sent to the AFK channel.
afk_channel: :class:`Channel` afk_channel: :class:`Channel`
The channel that denotes the AFK channel. None if it doesn't exist. The channel that denotes the AFK channel. None if it doesn't exist.
members members
An iterable of :class:`Member` that are currently on the server. An iterable of :class:`Member` that are currently on the guild.
channels channels
An iterable of :class:`Channel` that are currently on the server. An iterable of :class:`Channel` that are currently on the guild.
icon: str icon: str
The server's icon. The guild's icon.
id: int id: int
The server's ID. The guild's ID.
owner_id: int owner_id: int
The server owner's ID. Use :attr:`Server.owner` instead. The guild owner's ID. Use :attr:`Guild.owner` instead.
unavailable: bool unavailable: bool
Indicates if the server is unavailable. If this is ``True`` then the Indicates if the guild is unavailable. If this is ``True`` then the
reliability of other attributes outside of :meth:`Server.id` is slim and they might reliability of other attributes outside of :meth:`Guild.id` is slim and they might
all be None. It is best to not do anything with the server if it is unavailable. all be None. It is best to not do anything with the guild if it is unavailable.
Check the :func:`on_server_unavailable` and :func:`on_server_available` events. Check the :func:`on_guild_unavailable` and :func:`on_guild_available` events.
large: bool large: bool
Indicates if the server is a 'large' server. A large server is defined as having Indicates if the guild is a 'large' guild. A large guild is defined as having
more than ``large_threshold`` count members, which for this library is set to more than ``large_threshold`` count members, which for this library is set to
the maximum of 250. the maximum of 250.
voice_client: Optional[:class:`VoiceClient`] voice_client: Optional[:class:`VoiceClient`]
The VoiceClient associated with this server. A shortcut for the The VoiceClient associated with this guild. A shortcut for the
:meth:`Client.voice_client_in` call. :meth:`Client.voice_client_in` call.
mfa_level: int mfa_level: int
Indicates the server's two factor authorisation level. If this value is 0 then Indicates the guild's two factor authorisation level. If this value is 0 then
the server does not require 2FA for their administrative members. If the value is the guild does not require 2FA for their administrative members. If the value is
1 then they do. 1 then they do.
verification_level: :class:`VerificationLevel` verification_level: :class:`VerificationLevel`
The server's verification level. The guild's verification level.
features: List[str] features: List[str]
A list of features that the server has. They are currently as follows: A list of features that the guild has. They are currently as follows:
- ``VIP_REGIONS``: Server has VIP voice regions - ``VIP_REGIONS``: Guild has VIP voice regions
- ``VANITY_URL``: Server has a vanity invite URL (e.g. discord.gg/discord-api) - ``VANITY_URL``: Guild has a vanity invite URL (e.g. discord.gg/discord-api)
- ``INVITE_SPLASH``: Server's invite page has a special splash. - ``INVITE_SPLASH``: Guild's invite page has a special splash.
splash: str splash: str
The server's invite splash. The guild's invite splash.
""" """
__slots__ = ('afk_timeout', 'afk_channel', '_members', '_channels', 'icon', __slots__ = ('afk_timeout', 'afk_channel', '_members', '_channels', 'icon',
'name', 'id', 'unavailable', 'name', 'region', 'name', 'id', 'unavailable', 'name', 'region', '_state',
'_default_role', '_default_channel', 'roles', '_member_count', '_default_role', '_default_channel', 'roles', '_member_count',
'large', 'owner_id', 'mfa_level', 'emojis', 'features', 'large', 'owner_id', 'mfa_level', 'emojis', 'features',
'verification_level', 'splash', '_voice_states' ) 'verification_level', 'splash', '_voice_states' )
@ -218,19 +220,19 @@ class Server(Hashable):
def _from_data(self, guild): def _from_data(self, guild):
# according to Stan, this is always available even if the guild is unavailable # according to Stan, this is always available even if the guild is unavailable
# I don't have this guarantee when someone updates the server. # I don't have this guarantee when someone updates the guild.
member_count = guild.get('member_count', None) member_count = guild.get('member_count', None)
if member_count: if member_count:
self._member_count = member_count self._member_count = member_count
self.name = guild.get('name') self.name = guild.get('name')
self.region = try_enum(ServerRegion, guild.get('region')) self.region = try_enum(GuildRegion, guild.get('region'))
self.verification_level = try_enum(VerificationLevel, guild.get('verification_level')) self.verification_level = try_enum(VerificationLevel, guild.get('verification_level'))
self.afk_timeout = guild.get('afk_timeout') self.afk_timeout = guild.get('afk_timeout')
self.icon = guild.get('icon') self.icon = guild.get('icon')
self.unavailable = guild.get('unavailable', False) self.unavailable = guild.get('unavailable', False)
self.id = int(guild['id']) self.id = int(guild['id'])
self.roles = [Role(server=self, data=r, state=self._state) for r in guild.get('roles', [])] self.roles = [Role(guild=self, data=r, state=self._state) for r in guild.get('roles', [])]
self.mfa_level = guild.get('mfa_level') self.mfa_level = guild.get('mfa_level')
self.emojis = [Emoji(server=self, data=r, state=self._state) for r in guild.get('emojis', [])] self.emojis = [Emoji(server=self, data=r, state=self._state) for r in guild.get('emojis', [])]
self.features = guild.get('features', []) self.features = guild.get('features', [])
@ -244,7 +246,7 @@ class Server(Hashable):
roles.append(role) roles.append(role)
mdata['roles'] = roles mdata['roles'] = roles
member = Member(data=mdata, server=self, state=self._state) member = Member(data=mdata, guild=self, state=self._state)
self._add_member(member) self._add_member(member)
self._sync(guild) self._sync(guild)
@ -274,9 +276,9 @@ class Server(Hashable):
channels = data['channels'] channels = data['channels']
for c in channels: for c in channels:
if c['type'] == ChannelType.text.value: if c['type'] == ChannelType.text.value:
channel = TextChannel(server=self, data=c, state=self._state) channel = TextChannel(guild=self, data=c, state=self._state)
else: else:
channel = VoiceChannel(server=self, data=c, state=self._state) channel = VoiceChannel(guild=self, data=c, state=self._state)
self._add_channel(channel) self._add_channel(channel)
@ -287,17 +289,17 @@ class Server(Hashable):
@utils.cached_slot_property('_default_channel') @utils.cached_slot_property('_default_channel')
def default_channel(self): def default_channel(self):
"""Gets the default :class:`Channel` for the server.""" """Gets the default :class:`Channel` for the guild."""
return utils.find(lambda c: c.is_default, self.channels) return utils.find(lambda c: c.is_default, self.channels)
@property @property
def owner(self): def owner(self):
""":class:`Member`: The member that owns the server.""" """:class:`Member`: The member that owns the guild."""
return self.get_member(self.owner_id) return self.get_member(self.owner_id)
@property @property
def icon_url(self): def icon_url(self):
"""Returns the URL version of the server's icon. Returns an empty string if it has no icon.""" """Returns the URL version of the guild's icon. Returns an empty string if it has no icon."""
if self.icon is None: if self.icon is None:
return '' return ''
return 'https://discordapp.com/api/guilds/{0.id}/icons/{0.icon}.jpg'.format(self) return 'https://discordapp.com/api/guilds/{0.id}/icons/{0.icon}.jpg'.format(self)
@ -316,12 +318,12 @@ class Server(Hashable):
@property @property
def created_at(self): def created_at(self):
"""Returns the server's creation time in UTC.""" """Returns the guild's creation time in UTC."""
return utils.snowflake_time(self.id) return utils.snowflake_time(self.id)
@property @property
def role_hierarchy(self): def role_hierarchy(self):
"""Returns the server's roles in the order of the hierarchy. """Returns the guild's roles in the order of the hierarchy.
The first element of this list will be the highest role in the The first element of this list will be the highest role in the
hierarchy. hierarchy.
@ -351,7 +353,7 @@ class Server(Hashable):
Returns Returns
-------- --------
:class:`Member` :class:`Member`
The member in this server with the associated name. If not found The member in this guild with the associated name. If not found
then ``None`` is returned. then ``None`` is returned.
""" """

12
discord/http.py

@ -341,7 +341,7 @@ class HTTPClient:
url = '{0.GUILDS}/{1}/bans/{2}'.format(self, guild_id, user_id) url = '{0.GUILDS}/{1}/bans/{2}'.format(self, guild_id, user_id)
return self.delete(url, bucket=_func_()) return self.delete(url, bucket=_func_())
def server_voice_state(self, user_id, guild_id, *, mute=None, deafen=None): def guild_voice_state(self, user_id, guild_id, *, mute=None, deafen=None):
url = '{0.GUILDS}/{1}/members/{2}'.format(self, guild_id, user_id) url = '{0.GUILDS}/{1}/members/{2}'.format(self, guild_id, user_id)
payload = {} payload = {}
if mute is not None: if mute is not None:
@ -411,17 +411,17 @@ class HTTPClient:
url = '{0.CHANNELS}/{1}'.format(self, channel_id) url = '{0.CHANNELS}/{1}'.format(self, channel_id)
return self.delete(url, bucket=_func_()) return self.delete(url, bucket=_func_())
# Server management # Guild management
def leave_server(self, guild_id): def leave_guild(self, guild_id):
url = '{0.USERS}/@me/guilds/{1}'.format(self, guild_id) url = '{0.USERS}/@me/guilds/{1}'.format(self, guild_id)
return self.delete(url, bucket=_func_()) return self.delete(url, bucket=_func_())
def delete_server(self, guild_id): def delete_guild(self, guild_id):
url = '{0.GUILDS}/{1}'.format(self, guild_id) url = '{0.GUILDS}/{1}'.format(self, guild_id)
return self.delete(url, bucket=_func_()) return self.delete(url, bucket=_func_())
def create_server(self, name, region, icon): def create_guild(self, name, region, icon):
payload = { payload = {
'name': name, 'name': name,
'icon': icon, 'icon': icon,
@ -430,7 +430,7 @@ class HTTPClient:
return self.post(self.GUILDS, json=payload, bucket=_func_()) return self.post(self.GUILDS, json=payload, bucket=_func_())
def edit_server(self, guild_id, **fields): def edit_guild(self, guild_id, **fields):
valid_keys = ('name', 'region', 'icon', 'afk_timeout', 'owner_id', valid_keys = ('name', 'region', 'icon', 'afk_timeout', 'owner_id',
'afk_channel_id', 'splash', 'verification_level') 'afk_channel_id', 'splash', 'verification_level')

10
discord/invite.py

@ -29,7 +29,7 @@ from .utils import parse_time
from .mixins import Hashable from .mixins import Hashable
class Invite(Hashable): class Invite(Hashable):
"""Represents a Discord :class:`Server` or :class:`Channel` invite. """Represents a Discord :class:`Guild` or :class:`Channel` invite.
Depending on the way this object was created, some of the attributes can Depending on the way this object was created, some of the attributes can
have a value of ``None``. have a value of ``None``.
@ -54,8 +54,8 @@ class Invite(Hashable):
How long the before the invite expires in seconds. A value of 0 indicates that it doesn't expire. How long the before the invite expires in seconds. A value of 0 indicates that it doesn't expire.
code: str code: str
The URL fragment used for the invite. :attr:`xkcd` is also a possible fragment. The URL fragment used for the invite. :attr:`xkcd` is also a possible fragment.
server: :class:`Server` guild: :class:`Guild`
The server the invite is for. The guild the invite is for.
revoked: bool revoked: bool
Indicates if the invite has been revoked. Indicates if the invite has been revoked.
created_at: `datetime.datetime` created_at: `datetime.datetime`
@ -74,14 +74,14 @@ class Invite(Hashable):
""" """
__slots__ = ( 'max_age', 'code', 'server', 'revoked', 'created_at', 'uses', __slots__ = ( 'max_age', 'code', 'guild', 'revoked', 'created_at', 'uses',
'temporary', 'max_uses', 'inviter', 'channel', '_state' ) 'temporary', 'max_uses', 'inviter', 'channel', '_state' )
def __init__(self, *, state, data): def __init__(self, *, state, data):
self._state = state self._state = state
self.max_age = data.get('max_age') self.max_age = data.get('max_age')
self.code = data.get('code') self.code = data.get('code')
self.server = data.get('server') self.guild = data.get('guild')
self.revoked = data.get('revoked') self.revoked = data.get('revoked')
self.created_at = parse_time(data.get('created_at')) self.created_at = parse_time(data.get('created_at'))
self.temporary = data.get('temporary') self.temporary = data.get('temporary')

40
discord/member.py

@ -37,15 +37,15 @@ class VoiceState:
Attributes Attributes
------------ ------------
deaf: bool deaf: bool
Indicates if the user is currently deafened by the server. Indicates if the user is currently deafened by the guild.
mute: bool mute: bool
Indicates if the user is currently muted by the server. Indicates if the user is currently muted by the guild.
self_mute: bool self_mute: bool
Indicates if the user is currently muted by their own accord. Indicates if the user is currently muted by their own accord.
self_deaf: bool self_deaf: bool
Indicates if the user is currently deafened by their own accord. Indicates if the user is currently deafened by their own accord.
is_afk: bool is_afk: bool
Indicates if the user is currently in the AFK channel in the server. Indicates if the user is currently in the AFK channel in the guild.
channel: Optional[Union[:class:`Channel`, :class:`PrivateChannel`]] channel: Optional[Union[:class:`Channel`, :class:`PrivateChannel`]]
The voice channel that the user is currently connected to. None if the user The voice channel that the user is currently connected to. None if the user
is not currently in a voice channel. is not currently in a voice channel.
@ -99,7 +99,7 @@ def flatten_user(cls):
@flatten_user @flatten_user
class Member: class Member:
"""Represents a Discord member to a :class:`Server`. """Represents a Discord member to a :class:`Guild`.
This implements a lot of the functionality of :class:`User`. This implements a lot of the functionality of :class:`User`.
@ -123,22 +123,22 @@ class Member:
A list of :class:`Role` that the member belongs to. Note that the first element of this A list of :class:`Role` that the member belongs to. Note that the first element of this
list is always the default '@everyone' role. list is always the default '@everyone' role.
joined_at : `datetime.datetime` joined_at : `datetime.datetime`
A datetime object that specifies the date and time in UTC that the member joined the server for A datetime object that specifies the date and time in UTC that the member joined the guild for
the first time. the first time.
status : :class:`Status` status : :class:`Status`
The member's status. There is a chance that the status will be a ``str`` The member's status. There is a chance that the status will be a ``str``
if it is a value that is not recognised by the enumerator. if it is a value that is not recognised by the enumerator.
game : :class:`Game` game : :class:`Game`
The game that the user is currently playing. Could be None if no game is being played. The game that the user is currently playing. Could be None if no game is being played.
server : :class:`Server` guild : :class:`Guild`
The server that the member belongs to. The guild that the member belongs to.
nick : Optional[str] nick : Optional[str]
The server specific nickname of the user. The guild specific nickname of the user.
""" """
__slots__ = ('roles', 'joined_at', 'status', 'game', 'server', 'nick', '_user', '_state') __slots__ = ('roles', 'joined_at', 'status', 'game', 'guild', 'nick', '_user', '_state')
def __init__(self, *, data, server, state): def __init__(self, *, data, guild, state):
self._state = state self._state = state
self._user = state.try_insert_user(data['user']) self._user = state.try_insert_user(data['user'])
self.joined_at = utils.parse_time(data.get('joined_at')) self.joined_at = utils.parse_time(data.get('joined_at'))
@ -146,14 +146,14 @@ class Member:
self.status = Status.offline self.status = Status.offline
game = data.get('game', {}) game = data.get('game', {})
self.game = Game(**game) if game else None self.game = Game(**game) if game else None
self.server = server self.guild = guild
self.nick = data.get('nick', None) self.nick = data.get('nick', None)
def __str__(self): def __str__(self):
return self._user.__str__() return self._user.__str__()
def __eq__(self, other): def __eq__(self, other):
return isinstance(other, Member) and other._user.id == self._user.id and self.server.id == other.server.id return isinstance(other, Member) and other._user.id == self._user.id and self.guild.id == other.guild.id
def __ne__(self, other): def __ne__(self, other):
return not self.__eq__(other) return not self.__eq__(other)
@ -173,8 +173,8 @@ class Member:
self.nick = data['nick'] self.nick = data['nick']
# update the roles # update the roles
self.roles = [self.server.default_role] self.roles = [self.guild.default_role]
for role in self.server.roles: for role in self.guild.roles:
if role.id in data['roles']: if role.id in data['roles']:
self.roles.append(role) self.roles.append(role)
@ -254,20 +254,20 @@ class Member:
return None return None
@property @property
def server_permissions(self): def guild_permissions(self):
"""Returns the member's server permissions. """Returns the member's guild permissions.
This only takes into consideration the server permissions This only takes into consideration the guild permissions
and not most of the implied permissions or any of the and not most of the implied permissions or any of the
channel permission overwrites. For 100% accurate permission channel permission overwrites. For 100% accurate permission
calculation, please use either :meth:`permissions_in` or calculation, please use either :meth:`permissions_in` or
:meth:`Channel.permissions_for`. :meth:`Channel.permissions_for`.
This does take into consideration server ownership and the This does take into consideration guild ownership and the
administrator implication. administrator implication.
""" """
if self.server.owner == self: if self.guild.owner == self:
return Permissions.all() return Permissions.all()
base = Permissions.none() base = Permissions.none()
@ -282,4 +282,4 @@ class Member:
@property @property
def voice(self): def voice(self):
"""Optional[:class:`VoiceState`]: Returns the member's current voice state.""" """Optional[:class:`VoiceState`]: Returns the member's current voice state."""
return self.server._voice_state_for(self._user.id) return self.guild._voice_state_for(self._user.id)

32
discord/message.py

@ -54,7 +54,7 @@ class Message:
content: str content: str
The actual contents of the message. The actual contents of the message.
nonce nonce
The value used by the discord server and the client to verify that the message is successfully sent. The value used by the discord guild and the client to verify that the message is successfully sent.
This is typically non-important. This is typically non-important.
embeds: list embeds: list
A list of embedded objects. The elements are objects that meet oEmbed's specification_. A list of embedded objects. The elements are objects that meet oEmbed's specification_.
@ -66,8 +66,8 @@ class Message:
In :issue:`very rare cases <21>` this could be a :class:`Object` instead. In :issue:`very rare cases <21>` this could be a :class:`Object` instead.
For the sake of convenience, this :class:`Object` instance has an attribute ``is_private`` set to ``True``. For the sake of convenience, this :class:`Object` instance has an attribute ``is_private`` set to ``True``.
server: Optional[:class:`Server`] guild: Optional[:class:`Guild`]
The server that the message belongs to. If not applicable (i.e. a PM) then it's None instead. The guild that the message belongs to. If not applicable (i.e. a PM) then it's None instead.
call: Optional[:class:`CallMessage`] call: Optional[:class:`CallMessage`]
The call that the message refers to. This is only applicable to messages of type The call that the message refers to. This is only applicable to messages of type
:attr:`MessageType.call`. :attr:`MessageType.call`.
@ -112,7 +112,7 @@ class Message:
__slots__ = ( 'edited_timestamp', 'tts', 'content', 'channel', 'webhook_id', __slots__ = ( 'edited_timestamp', 'tts', 'content', 'channel', 'webhook_id',
'mention_everyone', 'embeds', 'id', 'mentions', 'author', 'mention_everyone', 'embeds', 'id', 'mentions', 'author',
'_cs_channel_mentions', 'server', '_cs_raw_mentions', 'attachments', '_cs_channel_mentions', 'guild', '_cs_raw_mentions', 'attachments',
'_cs_clean_content', '_cs_raw_channel_mentions', 'nonce', 'pinned', '_cs_clean_content', '_cs_raw_channel_mentions', 'nonce', 'pinned',
'role_mentions', '_cs_raw_role_mentions', 'type', 'call', 'role_mentions', '_cs_raw_role_mentions', 'type', 'call',
'_cs_system_content', '_state', 'reactions' ) '_cs_system_content', '_state', 'reactions' )
@ -160,21 +160,21 @@ class Message:
def _handle_mentions(self, mentions): def _handle_mentions(self, mentions):
self.mentions = [] self.mentions = []
if self.server is None: if self.guild is None:
self.mentions = [self._state.try_insert_user(m) for m in mentions] self.mentions = [self._state.try_insert_user(m) for m in mentions]
return return
for mention in mentions: for mention in mentions:
id_search = int(mention['id']) id_search = int(mention['id'])
member = self.server.get_member(id_search) member = self.guild.get_member(id_search)
if member is not None: if member is not None:
self.mentions.append(member) self.mentions.append(member)
def _handle_mention_roles(self, role_mentions): def _handle_mention_roles(self, role_mentions):
self.role_mentions = [] self.role_mentions = []
if self.server is not None: if self.guild is not None:
for role_id in role_mentions: for role_id in role_mentions:
role = utils.get(self.server.roles, id=role_id) role = utils.get(self.guild.roles, id=role_id)
if role is not None: if role is not None:
self.role_mentions.append(role) self.role_mentions.append(role)
@ -224,9 +224,9 @@ class Message:
@utils.cached_slot_property('_cs_channel_mentions') @utils.cached_slot_property('_cs_channel_mentions')
def channel_mentions(self): def channel_mentions(self):
if self.server is None: if self.guild is None:
return [] return []
it = filter(None, map(lambda m: self.server.get_channel(m), self.raw_channel_mentions)) it = filter(None, map(lambda m: self.guild.get_channel(m), self.raw_channel_mentions))
return utils._unique(it) return utils._unique(it)
@utils.cached_slot_property('_cs_clean_content') @utils.cached_slot_property('_cs_clean_content')
@ -259,7 +259,7 @@ class Message:
transformations.update(mention_transforms) transformations.update(mention_transforms)
transformations.update(second_mention_transforms) transformations.update(second_mention_transforms)
if self.server is not None: if self.guild is not None:
role_transforms = { role_transforms = {
re.escape('<@&{0.id}>'.format(role)): '@' + role.name re.escape('<@&{0.id}>'.format(role)): '@' + role.name
for role in self.role_mentions for role in self.role_mentions
@ -284,7 +284,7 @@ class Message:
return pattern.sub(repl2, result) return pattern.sub(repl2, result)
def _handle_upgrades(self, channel_id): def _handle_upgrades(self, channel_id):
self.server = None self.guild = None
if isinstance(self.channel, Object): if isinstance(self.channel, Object):
return return
@ -295,8 +295,8 @@ class Message:
return return
if isinstance(self.channel, abc.GuildChannel): if isinstance(self.channel, abc.GuildChannel):
self.server = self.channel.server self.guild = self.channel.guild
found = self.server.get_member(self.author.id) found = self.guild.get_member(self.author.id)
if found is not None: if found is not None:
self.author = found self.author = found
@ -363,7 +363,7 @@ class Message:
HTTPException HTTPException
Deleting the message failed. Deleting the message failed.
""" """
yield from self._state.http.delete_message(self.channel.id, self.id, getattr(self.server, 'id', None)) yield from self._state.http.delete_message(self.channel.id, self.id, getattr(self.guild, 'id', None))
@asyncio.coroutine @asyncio.coroutine
def edit(self, *, content: str): def edit(self, *, content: str):
@ -384,7 +384,7 @@ class Message:
Editing the message failed. Editing the message failed.
""" """
guild_id = getattr(self.server, 'id', None) guild_id = getattr(self.guild, 'id', None)
data = yield from self._state.http.edit_message(self.id, self.channel.id, str(content), guild_id=guild_id) data = yield from self._state.http.edit_message(self.id, self.channel.id, str(content), guild_id=guild_id)
self._update(channel=self.channel, data=data) self._update(channel=self.channel, data=data)

24
discord/permissions.py

@ -132,10 +132,10 @@ class Permissions:
@classmethod @classmethod
def all_channel(cls): def all_channel(cls):
"""A :class:`Permissions` with all channel-specific permissions set to """A :class:`Permissions` with all channel-specific permissions set to
True and the server-specific ones set to False. The server-specific True and the guild-specific ones set to False. The guild-specific
permissions are currently: permissions are currently:
- manager_server - manager_guild
- kick_members - kick_members
- ban_members - ban_members
- administrator - administrator
@ -220,7 +220,7 @@ class Permissions:
@property @property
def kick_members(self): def kick_members(self):
"""Returns True if the user can kick users from the server.""" """Returns True if the user can kick users from the guild."""
return self._bit(1) return self._bit(1)
@kick_members.setter @kick_members.setter
@ -229,7 +229,7 @@ class Permissions:
@property @property
def ban_members(self): def ban_members(self):
"""Returns True if a user can ban users from the server.""" """Returns True if a user can ban users from the guild."""
return self._bit(2) return self._bit(2)
@ban_members.setter @ban_members.setter
@ -250,7 +250,7 @@ class Permissions:
@property @property
def manage_channels(self): def manage_channels(self):
"""Returns True if a user can edit, delete, or create channels in the server. """Returns True if a user can edit, delete, or create channels in the guild.
This also corresponds to the "manage channel" channel-specific override.""" This also corresponds to the "manage channel" channel-specific override."""
return self._bit(4) return self._bit(4)
@ -260,12 +260,12 @@ class Permissions:
self._set(4, value) self._set(4, value)
@property @property
def manage_server(self): def manage_guild(self):
"""Returns True if a user can edit server properties.""" """Returns True if a user can edit guild properties."""
return self._bit(5) return self._bit(5)
@manage_server.setter @manage_guild.setter
def manage_server(self, value): def manage_guild(self, value):
self._set(5, value) self._set(5, value)
@property @property
@ -353,7 +353,7 @@ class Permissions:
@property @property
def external_emojis(self): def external_emojis(self):
"""Returns True if a user can use emojis from other servers.""" """Returns True if a user can use emojis from other guilds."""
return self._bit(18) return self._bit(18)
@external_emojis.setter @external_emojis.setter
@ -418,7 +418,7 @@ class Permissions:
@property @property
def change_nickname(self): def change_nickname(self):
"""Returns True if a user can change their nickname in the server.""" """Returns True if a user can change their nickname in the guild."""
return self._bit(26) return self._bit(26)
@change_nickname.setter @change_nickname.setter
@ -427,7 +427,7 @@ class Permissions:
@property @property
def manage_nicknames(self): def manage_nicknames(self):
"""Returns True if a user can change other user's nickname in the server.""" """Returns True if a user can change other user's nickname in the guild."""
return self._bit(27) return self._bit(27)
@manage_nicknames.setter @manage_nicknames.setter

20
discord/role.py

@ -30,7 +30,7 @@ from .mixins import Hashable
from .utils import snowflake_time from .utils import snowflake_time
class Role(Hashable): class Role(Hashable):
"""Represents a Discord role in a :class:`Server`. """Represents a Discord role in a :class:`Guild`.
Supported Operations: Supported Operations:
@ -62,8 +62,8 @@ class Role(Hashable):
The name of the role. The name of the role.
permissions: :class:`Permissions` permissions: :class:`Permissions`
Represents the role's permissions. Represents the role's permissions.
server: :class:`Server` guild: :class:`Guild`
The server the role belongs to. The guild the role belongs to.
colour: :class:`Colour` colour: :class:`Colour`
Represents the role colour. An alias exists under ``color``. Represents the role colour. An alias exists under ``color``.
hoist: bool hoist: bool
@ -72,17 +72,17 @@ class Role(Hashable):
The position of the role. This number is usually positive. The bottom The position of the role. This number is usually positive. The bottom
role has a position of 0. role has a position of 0.
managed: bool managed: bool
Indicates if the role is managed by the server through some form of Indicates if the role is managed by the guild through some form of
integrations such as Twitch. integrations such as Twitch.
mentionable: bool mentionable: bool
Indicates if the role can be mentioned by users. Indicates if the role can be mentioned by users.
""" """
__slots__ = ('id', 'name', 'permissions', 'color', 'colour', 'position', __slots__ = ('id', 'name', 'permissions', 'color', 'colour', 'position',
'managed', 'mentionable', 'hoist', 'server', '_state' ) 'managed', 'mentionable', 'hoist', 'guild', '_state' )
def __init__(self, *, server, state, data): def __init__(self, *, guild, state, data):
self.server = server self.guild = guild
self._state = state self._state = state
self.id = int(data['id']) self.id = int(data['id'])
self._update(data) self._update(data)
@ -94,8 +94,8 @@ class Role(Hashable):
if not isinstance(other, Role) or not isinstance(self, Role): if not isinstance(other, Role) or not isinstance(self, Role):
return NotImplemented return NotImplemented
if self.server != other.server: if self.guild != other.guild:
raise RuntimeError('cannot compare roles from two different servers.') raise RuntimeError('cannot compare roles from two different guilds.')
if self.position < other.position: if self.position < other.position:
return True return True
@ -133,7 +133,7 @@ class Role(Hashable):
@property @property
def is_everyone(self): def is_everyone(self):
"""Checks if the role is the @everyone role.""" """Checks if the role is the @everyone role."""
return self.server.id == self.id return self.guild.id == self.id
@property @property
def created_at(self): def created_at(self):

276
discord/state.py

@ -24,7 +24,7 @@ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE. DEALINGS IN THE SOFTWARE.
""" """
from .server import Server from .guild import Guild
from .user import User from .user import User
from .game import Game from .game import Game
from .emoji import Emoji from .emoji import Emoji
@ -49,7 +49,7 @@ class ListenerType(enum.Enum):
Listener = namedtuple('Listener', ('type', 'future', 'predicate')) Listener = namedtuple('Listener', ('type', 'future', 'predicate'))
StateContext = namedtuple('StateContext', 'try_insert_user http') StateContext = namedtuple('StateContext', 'try_insert_user http')
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
ReadyState = namedtuple('ReadyState', ('launch', 'servers')) ReadyState = namedtuple('ReadyState', ('launch', 'guilds'))
class ConnectionState: class ConnectionState:
def __init__(self, *, dispatch, chunker, syncer, http, loop, **options): def __init__(self, *, dispatch, chunker, syncer, http, loop, **options):
@ -69,7 +69,7 @@ class ConnectionState:
self.session_id = None self.session_id = None
self._calls = {} self._calls = {}
self._users = {} self._users = {}
self._servers = {} self._guilds = {}
self._voice_clients = {} self._voice_clients = {}
self._private_channels = {} self._private_channels = {}
# extra dict to look up private channels by user id # extra dict to look up private channels by user id
@ -129,17 +129,17 @@ class ConnectionState:
return user return user
@property @property
def servers(self): def guilds(self):
return self._servers.values() return self._guilds.values()
def _get_server(self, server_id): def _get_guild(self, guild_id):
return self._servers.get(server_id) return self._guilds.get(guild_id)
def _add_server(self, server): def _add_guild(self, guild):
self._servers[server.id] = server self._guilds[guild.id] = guild
def _remove_server(self, server): def _remove_guild(self, guild):
self._servers.pop(server.id, None) self._guilds.pop(guild.id, None)
@property @property
def private_channels(self): def private_channels(self):
@ -164,16 +164,16 @@ class ConnectionState:
def _get_message(self, msg_id): def _get_message(self, msg_id):
return utils.find(lambda m: m.id == msg_id, self.messages) return utils.find(lambda m: m.id == msg_id, self.messages)
def _add_server_from_data(self, guild): def _add_guild_from_data(self, guild):
server = Server(data=guild, state=self.ctx) guild = Guild(data=guild, state=self.ctx)
Server.me = property(lambda s: s.get_member(self.user.id)) Guild.me = property(lambda s: s.get_member(self.user.id))
Server.voice_client = property(lambda s: self._get_voice_client(s.id)) Guild.voice_client = property(lambda s: self._get_voice_client(s.id))
self._add_server(server) self._add_guild(guild)
return server return guild
def chunks_needed(self, server): def chunks_needed(self, guild):
for chunk in range(math.ceil(server._member_count / 1000)): for chunk in range(math.ceil(guild._member_count / 1000)):
yield self.receive_chunk(server.id) yield self.receive_chunk(guild.id)
@asyncio.coroutine @asyncio.coroutine
def _delay_ready(self): def _delay_ready(self):
@ -184,15 +184,15 @@ class ConnectionState:
launch.set() launch.set()
yield from asyncio.sleep(2, loop=self.loop) yield from asyncio.sleep(2, loop=self.loop)
servers = self._ready_state.servers guilds = self._ready_state.guilds
# get all the chunks # get all the chunks
chunks = [] chunks = []
for server in servers: for guild in guilds:
chunks.extend(self.chunks_needed(server)) chunks.extend(self.chunks_needed(guild))
# we only want to request ~75 guilds per chunk request. # we only want to request ~75 guilds per chunk request.
splits = [servers[i:i + 75] for i in range(0, len(servers), 75)] splits = [guilds[i:i + 75] for i in range(0, len(guilds), 75)]
for split in splits: for split in splits:
yield from self.chunker(split) yield from self.chunker(split)
@ -211,22 +211,22 @@ class ConnectionState:
# call GUILD_SYNC after we're done chunking # call GUILD_SYNC after we're done chunking
if not self.is_bot: if not self.is_bot:
log.info('Requesting GUILD_SYNC for %s guilds' % len(self.servers)) log.info('Requesting GUILD_SYNC for %s guilds' % len(self.guilds))
yield from self.syncer([s.id for s in self.servers]) yield from self.syncer([s.id for s in self.guilds])
# dispatch the event # dispatch the event
self.dispatch('ready') self.dispatch('ready')
def parse_ready(self, data): def parse_ready(self, data):
self._ready_state = ReadyState(launch=asyncio.Event(), servers=[]) self._ready_state = ReadyState(launch=asyncio.Event(), guilds=[])
self.user = self.try_insert_user(data['user']) self.user = self.try_insert_user(data['user'])
guilds = data.get('guilds') guilds = data.get('guilds')
servers = self._ready_state.servers guilds = self._ready_state.guilds
for guild in guilds: for guild_data in guilds:
server = self._add_server_from_data(guild) guild = self._add_server_from_data(guild_data)
if not self.is_bot or server.large: if not self.is_bot or guild.large:
servers.append(server) guilds.append(guild)
for pm in data.get('private_channels'): for pm in data.get('private_channels'):
factory, _ = _channel_factory(pm['type']) factory, _ = _channel_factory(pm['type'])
@ -324,22 +324,22 @@ class ConnectionState:
self.dispatch('reaction_remove', reaction, member) self.dispatch('reaction_remove', reaction, member)
def parse_presence_update(self, data): def parse_presence_update(self, data):
server = self._get_server(utils._get_as_snowflake(data, 'guild_id')) guild = self._get_guild(utils._get_as_snowflake(data, 'guild_id'))
if server is None: if guild is None:
return return
status = data.get('status') status = data.get('status')
user = data['user'] user = data['user']
member_id = user['id'] member_id = user['id']
member = server.get_member(member_id) member = guild.get_member(member_id)
if member is None: if member is None:
if 'username' not in user: if 'username' not in user:
# sometimes we receive 'incomplete' member data post-removal. # sometimes we receive 'incomplete' member data post-removal.
# skip these useless cases. # skip these useless cases.
return return
member = self._make_member(server, data) member = self._make_member(guild, data)
server._add_member(member) guild._add_member(member)
old_member = copy.copy(member) old_member = copy.copy(member)
member._presence_update(data=data, user=user) member._presence_update(data=data, user=user)
@ -349,12 +349,12 @@ class ConnectionState:
self.user = User(state=self.ctx, data=data) self.user = User(state=self.ctx, data=data)
def parse_channel_delete(self, data): def parse_channel_delete(self, data):
server = self._get_server(utils._get_as_snowflake(data, 'guild_id')) guild = self._get_guild(utils._get_as_snowflake(data, 'guild_id'))
channel_id = int(data['id']) channel_id = int(data['id'])
if server is not None: if guild is not None:
channel = server.get_channel(channel_id) channel = guild.get_channel(channel_id)
if channel is not None: if channel is not None:
server._remove_channel(channel) guild._remove_channel(channel)
self.dispatch('channel_delete', channel) self.dispatch('channel_delete', channel)
else: else:
# the reason we're doing this is so it's also removed from the # the reason we're doing this is so it's also removed from the
@ -372,12 +372,12 @@ class ConnectionState:
self.dispatch('channel_update', old_channel, channel) self.dispatch('channel_update', old_channel, channel)
return return
server = self._get_server(utils._get_as_snowflake(data, 'guild_id')) guild = self._get_guild(utils._get_as_snowflake(data, 'guild_id'))
if server is not None: if guild is not None:
channel = server.get_channel(channel_id) channel = guild.get_channel(channel_id)
if channel is not None: if channel is not None:
old_channel = copy.copy(channel) old_channel = copy.copy(channel)
channel._update(server, data) channel._update(guild, data)
self.dispatch('channel_update', old_channel, channel) self.dispatch('channel_update', old_channel, channel)
def parse_channel_create(self, data): def parse_channel_create(self, data):
@ -387,10 +387,10 @@ class ConnectionState:
channel = factory(me=self.user, data=data, state=self.ctx) channel = factory(me=self.user, data=data, state=self.ctx)
self._add_private_channel(channel) self._add_private_channel(channel)
else: else:
server = self._get_server(utils._get_as_snowflake(data, 'guild_id')) guild = self._get_guild(utils._get_as_snowflake(data, 'guild_id'))
if server is not None: if guild is not None:
channel = factory(server=server, state=self.ctx, data=data) channel = factory(guild=guild, state=self.ctx, data=data)
server._add_channel(channel) guild._add_channel(channel)
self.dispatch('channel_create', channel) self.dispatch('channel_create', channel)
@ -410,34 +410,34 @@ class ConnectionState:
else: else:
self.dispatch('group_remove', channel, user) self.dispatch('group_remove', channel, user)
def _make_member(self, server, data): def _make_member(self, guild, data):
roles = [server.default_role] roles = [guild.default_role]
for roleid in data.get('roles', []): for roleid in data.get('roles', []):
role = utils.get(server.roles, id=roleid) role = utils.get(guild.roles, id=roleid)
if role is not None: if role is not None:
roles.append(role) roles.append(role)
data['roles'] = sorted(roles, key=lambda r: r.id) data['roles'] = sorted(roles, key=lambda r: r.id)
return Member(server=server, data=data, state=self.ctx) return Member(guild=guild, data=data, state=self.ctx)
def parse_guild_member_add(self, data): def parse_guild_member_add(self, data):
server = self._get_server(int(data['guild_id'])) guild = self._get_guild(int(data['guild_id']))
member = self._make_member(server, data) member = self._make_member(guild, data)
server._add_member(member) guild._add_member(member)
server._member_count += 1 guild._member_count += 1
self.dispatch('member_join', member) self.dispatch('member_join', member)
def parse_guild_member_remove(self, data): def parse_guild_member_remove(self, data):
server = self._get_server(int(data['guild_id'])) guild = self._get_guild(int(data['guild_id']))
if server is not None: if guild is not None:
user_id = data['user']['id'] user_id = data['user']['id']
member = server.get_member(user_id) member = guild.get_member(user_id)
if member is not None: if member is not None:
server._remove_member(member) guild._remove_member(member)
server._member_count -= 1 guild._member_count -= 1
# remove them from the voice channel member list # remove them from the voice channel member list
vc = server._voice_state_for(user_id) vc = guild._voice_state_for(user_id)
if vc: if vc:
voice_channel = vc.channel voice_channel = vc.channel
if voice_channel is not None: if voice_channel is not None:
@ -449,38 +449,38 @@ class ConnectionState:
self.dispatch('member_remove', member) self.dispatch('member_remove', member)
def parse_guild_member_update(self, data): def parse_guild_member_update(self, data):
server = self._get_server(int(data['guild_id'])) guild = self._get_guild(int(data['guild_id']))
user = data['user'] user = data['user']
user_id = user['id'] user_id = user['id']
member = server.get_member(user_id) member = guild.get_member(user_id)
if member is not None: if member is not None:
old_member = copy.copy(member) old_member = copy.copy(member)
member._update(data, user) member._update(data, user)
self.dispatch('member_update', old_member, member) self.dispatch('member_update', old_member, member)
def parse_guild_emojis_update(self, data): def parse_guild_emojis_update(self, data):
server = self._get_server(int(data['guild_id'])) guild = self._get_guild(int(data['guild_id']))
before_emojis = server.emojis before_emojis = guild.emojis
server.emojis = [Emoji(server=server, data=e, state=self.ctx) for e in data.get('emojis', [])] guild.emojis = [Emoji(guild=guild, data=e, state=self.ctx) for e in data.get('emojis', [])]
self.dispatch('server_emojis_update', before_emojis, server.emojis) self.dispatch('guild_emojis_update', before_emojis, guild.emojis)
def _get_create_server(self, data): def _get_create_guild(self, data):
if data.get('unavailable') == False: if data.get('unavailable') == False:
# GUILD_CREATE with unavailable in the response # GUILD_CREATE with unavailable in the response
# usually means that the server has become available # usually means that the guild has become available
# and is therefore in the cache # and is therefore in the cache
server = self._get_server(data.get('id')) guild = self._get_guild(data.get('id'))
if server is not None: if guild is not None:
server.unavailable = False guild.unavailable = False
server._from_data(data) guild._from_data(data)
return server return guild
return self._add_server_from_data(data) return self._add_guild_from_data(data)
@asyncio.coroutine @asyncio.coroutine
def _chunk_and_dispatch(self, server, unavailable): def _chunk_and_dispatch(self, guild, unavailable):
yield from self.chunker(server) yield from self.chunker(guild)
chunks = list(self.chunks_needed(server)) chunks = list(self.chunks_needed(guild))
if chunks: if chunks:
try: try:
yield from asyncio.wait(chunks, timeout=len(chunks), loop=self.loop) yield from asyncio.wait(chunks, timeout=len(chunks), loop=self.loop)
@ -488,30 +488,30 @@ class ConnectionState:
log.info('Somehow timed out waiting for chunks.') log.info('Somehow timed out waiting for chunks.')
if unavailable == False: if unavailable == False:
self.dispatch('server_available', server) self.dispatch('guild_available', guild)
else: else:
self.dispatch('server_join', server) self.dispatch('guild_join', guild)
def parse_guild_create(self, data): def parse_guild_create(self, data):
unavailable = data.get('unavailable') unavailable = data.get('unavailable')
if unavailable == True: if unavailable == True:
# joined a server with unavailable == True so.. # joined a guild with unavailable == True so..
return return
server = self._get_create_server(data) guild = self._get_create_guild(data)
# check if it requires chunking # check if it requires chunking
if server.large: if guild.large:
if unavailable == False: if unavailable == False:
# check if we're waiting for 'useful' READY # check if we're waiting for 'useful' READY
# and if we are, we don't want to dispatch any # and if we are, we don't want to dispatch any
# event such as server_join or server_available # event such as guild_join or guild_available
# because we're still in the 'READY' phase. Or # because we're still in the 'READY' phase. Or
# so we say. # so we say.
try: try:
state = self._ready_state state = self._ready_state
state.launch.clear() state.launch.clear()
state.servers.append(server) state.guilds.append(guild)
except AttributeError: except AttributeError:
# the _ready_state attribute is only there during # the _ready_state attribute is only there during
# processing of useful READY. # processing of useful READY.
@ -521,43 +521,43 @@ class ConnectionState:
# since we're not waiting for 'useful' READY we'll just # since we're not waiting for 'useful' READY we'll just
# do the chunk request here # do the chunk request here
compat.create_task(self._chunk_and_dispatch(server, unavailable), loop=self.loop) compat.create_task(self._chunk_and_dispatch(guild, unavailable), loop=self.loop)
return return
# Dispatch available if newly available # Dispatch available if newly available
if unavailable == False: if unavailable == False:
self.dispatch('server_available', server) self.dispatch('guild_available', guild)
else: else:
self.dispatch('server_join', server) self.dispatch('guild_join', guild)
def parse_guild_sync(self, data): def parse_guild_sync(self, data):
server = self._get_server(int(data['id'])) guild = self._get_guild(int(data['id']))
server._sync(data) guild._sync(data)
def parse_guild_update(self, data): def parse_guild_update(self, data):
server = self._get_server(int(data['id'])) guild = self._get_guild(int(data['id']))
if server is not None: if guild is not None:
old_server = copy.copy(server) old_guild = copy.copy(guild)
server._from_data(data) guild._from_data(data)
self.dispatch('server_update', old_server, server) self.dispatch('guild_update', old_guild, guild)
def parse_guild_delete(self, data): def parse_guild_delete(self, data):
server = self._get_server(int(data['id'])) guild = self._get_guild(int(data['id']))
if server is None: if guild is None:
return return
if data.get('unavailable', False) and server is not None: if data.get('unavailable', False) and guild is not None:
# GUILD_DELETE with unavailable being True means that the # GUILD_DELETE with unavailable being True means that the
# server that was available is now currently unavailable # guild that was available is now currently unavailable
server.unavailable = True guild.unavailable = True
self.dispatch('server_unavailable', server) self.dispatch('guild_unavailable', guild)
return return
# do a cleanup of the messages cache # do a cleanup of the messages cache
self.messages = deque((msg for msg in self.messages if msg.server != server), maxlen=self.max_messages) self.messages = deque((msg for msg in self.messages if msg.guild != guild), maxlen=self.max_messages)
self._remove_server(server) self._remove_guild(guild)
self.dispatch('server_remove', server) self.dispatch('guild_remove', guild)
def parse_guild_ban_add(self, data): def parse_guild_ban_add(self, data):
# we make the assumption that GUILD_BAN_ADD is done # we make the assumption that GUILD_BAN_ADD is done
@ -565,72 +565,72 @@ class ConnectionState:
# hence we don't remove it from cache or do anything # hence we don't remove it from cache or do anything
# strange with it, the main purpose of this event # strange with it, the main purpose of this event
# is mainly to dispatch to another event worth listening to for logging # is mainly to dispatch to another event worth listening to for logging
server = self._get_server(int(data['guild_id'])) guild = self._get_guild(int(data['guild_id']))
if server is not None: if guild is not None:
user_id = data.get('user', {}).get('id') user_id = data.get('user', {}).get('id')
member = utils.get(server.members, id=user_id) member = utils.get(guild.members, id=user_id)
if member is not None: if member is not None:
self.dispatch('member_ban', member) self.dispatch('member_ban', member)
def parse_guild_ban_remove(self, data): def parse_guild_ban_remove(self, data):
server = self._get_server(int(data['guild_id'])) guild = self._get_guild(int(data['guild_id']))
if server is not None: if guild is not None:
if 'user' in data: if 'user' in data:
user = self.try_insert_user(data['user']) user = self.try_insert_user(data['user'])
self.dispatch('member_unban', server, user) self.dispatch('member_unban', guild, user)
def parse_guild_role_create(self, data): def parse_guild_role_create(self, data):
server = self._get_server(int(data['guild_id'])) guild = self._get_guild(int(data['guild_id']))
role_data = data['role'] role_data = data['role']
role = Role(server=server, data=role_data, state=self.ctx) role = Role(guild=guild, data=role_data, state=self.ctx)
server._add_role(role) guild._add_role(role)
self.dispatch('server_role_create', role) self.dispatch('guild_role_create', role)
def parse_guild_role_delete(self, data): def parse_guild_role_delete(self, data):
server = self._get_server(int(data['guild_id'])) guild = self._get_guild(int(data['guild_id']))
if server is not None: if guild is not None:
role_id = data.get('role_id') role_id = data.get('role_id')
role = utils.find(lambda r: r.id == role_id, server.roles) role = utils.find(lambda r: r.id == role_id, guild.roles)
try: try:
server._remove_role(role) guild._remove_role(role)
except ValueError: except ValueError:
return return
else: else:
self.dispatch('server_role_delete', role) self.dispatch('guild_role_delete', role)
def parse_guild_role_update(self, data): def parse_guild_role_update(self, data):
server = self._get_server(int(data['guild_id'])) guild = self._get_guild(int(data['guild_id']))
if server is not None: if guild is not None:
role_data = data['role'] role_data = data['role']
role_id = role_data['id'] role_id = role_data['id']
role = utils.find(lambda r: r.id == role_id, server.roles) role = utils.find(lambda r: r.id == role_id, guild.roles)
if role is not None: if role is not None:
old_role = copy.copy(role) old_role = copy.copy(role)
role._update(role_data) role._update(role_data)
self.dispatch('server_role_update', old_role, role) self.dispatch('guild_role_update', old_role, role)
def parse_guild_members_chunk(self, data): def parse_guild_members_chunk(self, data):
server = self._get_server(int(data['guild_id'])) guild = self._get_guild(int(data['guild_id']))
members = data.get('members', []) members = data.get('members', [])
for member in members: for member in members:
m = self._make_member(server, member) m = self._make_member(guild, member)
existing = server.get_member(m.id) existing = guild.get_member(m.id)
if existing is None or existing.joined_at is None: if existing is None or existing.joined_at is None:
server._add_member(m) guild._add_member(m)
log.info('processed a chunk for {} members.'.format(len(members))) log.info('processed a chunk for {} members.'.format(len(members)))
self.process_listeners(ListenerType.chunk, server, len(members)) self.process_listeners(ListenerType.chunk, guild, len(members))
def parse_voice_state_update(self, data): def parse_voice_state_update(self, data):
server = self._get_server(utils._get_as_snowflake(data, 'guild_id')) guild = self._get_guild(utils._get_as_snowflake(data, 'guild_id'))
channel_id = utils._get_as_snowflake(data, 'channel_id') channel_id = utils._get_as_snowflake(data, 'channel_id')
if server is not None: if guild is not None:
if int(data['user_id']) == self.user.id: if int(data['user_id']) == self.user.id:
voice = self._get_voice_client(server.id) voice = self._get_voice_client(guild.id)
if voice is not None: if voice is not None:
voice.channel = server.get_channel(channel_id) voice.channel = guild.get_channel(channel_id)
member, before, after = server._update_voice_state(data, channel_id) member, before, after = guild._update_voice_state(data, channel_id)
if after is not None: if after is not None:
self.dispatch('voice_state_update', member, before, after) self.dispatch('voice_state_update', member, before, after)
else: else:
@ -647,7 +647,7 @@ class ConnectionState:
if isinstance(channel, DMChannel): if isinstance(channel, DMChannel):
member = channel.recipient member = channel.recipient
elif isinstance(channel, TextChannel): elif isinstance(channel, TextChannel):
member = channel.server.get_member(user_id) member = channel.guild.get_member(user_id)
elif isinstance(channel, GroupChannel): elif isinstance(channel, GroupChannel):
member = utils.find(lambda x: x.id == user_id, channel.recipients) member = utils.find(lambda x: x.id == user_id, channel.recipients)
@ -708,8 +708,8 @@ class ConnectionState:
if id is None: if id is None:
return None return None
for server in self.servers: for guild in self.guilds:
channel = server.get_channel(id) channel = guild.get_channel(id)
if channel is not None: if channel is not None:
return channel return channel

2
discord/user.py

@ -136,7 +136,7 @@ class User:
"""Returns the user's display name. """Returns the user's display name.
For regular users this is just their username, but For regular users this is just their username, but
if they have a server specific nickname then that if they have a guild specific nickname then that
is returned instead. is returned instead.
""" """
return getattr(self, 'nick', None) or self.name return getattr(self, 'nick', None) or self.name

20
discord/utils.py

@ -91,9 +91,9 @@ def deprecated(instead=None):
return decorated return decorated
return actual_decorator return actual_decorator
def oauth_url(client_id, permissions=None, server=None, redirect_uri=None): def oauth_url(client_id, permissions=None, guild=None, redirect_uri=None):
"""A helper function that returns the OAuth2 URL for inviting the bot """A helper function that returns the OAuth2 URL for inviting the bot
into servers. into guilds.
Parameters Parameters
----------- -----------
@ -102,16 +102,16 @@ def oauth_url(client_id, permissions=None, server=None, redirect_uri=None):
permissions : :class:`Permissions` permissions : :class:`Permissions`
The permissions you're requesting. If not given then you won't be requesting any The permissions you're requesting. If not given then you won't be requesting any
permissions. permissions.
server : :class:`Server` guild : :class:`Guild`
The server to pre-select in the authorization screen, if available. The guild to pre-select in the authorization screen, if available.
redirect_uri : str redirect_uri : str
An optional valid redirect URI. An optional valid redirect URI.
""" """
url = 'https://discordapp.com/oauth2/authorize?client_id={}&scope=bot'.format(client_id) url = 'https://discordapp.com/oauth2/authorize?client_id={}&scope=bot'.format(client_id)
if permissions is not None: if permissions is not None:
url = url + '&permissions=' + str(permissions.value) url = url + '&permissions=' + str(permissions.value)
if server is not None: if guild is not None:
url = url + "&guild_id=" + server.id url = url + "&guild_id=" + guild.id
if redirect_uri is not None: if redirect_uri is not None:
from urllib.parse import urlencode from urllib.parse import urlencode
url = url + "&response_type=code&" + urlencode({'redirect_uri': redirect_uri}) url = url + "&response_type=code&" + urlencode({'redirect_uri': redirect_uri})
@ -144,7 +144,7 @@ def find(predicate, seq):
"""A helper to return the first element found in the sequence """A helper to return the first element found in the sequence
that meets the predicate. For example: :: that meets the predicate. For example: ::
member = find(lambda m: m.name == 'Mighty', channel.server.members) member = find(lambda m: m.name == 'Mighty', channel.guild.members)
would find the first :class:`Member` whose name is 'Mighty' and return it. would find the first :class:`Member` whose name is 'Mighty' and return it.
If an entry is not found, then ``None`` is returned. If an entry is not found, then ``None`` is returned.
@ -190,19 +190,19 @@ def get(iterable, **attrs):
.. code-block:: python .. code-block:: python
member = discord.utils.get(message.server.members, name='Foo') member = discord.utils.get(message.guild.members, name='Foo')
Multiple attribute matching: Multiple attribute matching:
.. code-block:: python .. code-block:: python
channel = discord.utils.get(server.channels, name='Foo', type=ChannelType.voice) channel = discord.utils.get(guild.channels, name='Foo', type=ChannelType.voice)
Nested attribute matching: Nested attribute matching:
.. code-block:: python .. code-block:: python
channel = discord.utils.get(client.get_all_channels(), server__name='Cool', name='general') channel = discord.utils.get(client.get_all_channels(), guild__name='Cool', name='general')
Parameters Parameters
----------- -----------

12
discord/voice_client.py

@ -26,7 +26,7 @@ DEALINGS IN THE SOFTWARE.
"""Some documentation to refer to: """Some documentation to refer to:
- Our main web socket (mWS) sends opcode 4 with a server ID and channel ID. - Our main web socket (mWS) sends opcode 4 with a guild ID and channel ID.
- The mWS receives VOICE_STATE_UPDATE and VOICE_SERVER_UPDATE. - The mWS receives VOICE_STATE_UPDATE and VOICE_SERVER_UPDATE.
- We pull the session_id from VOICE_STATE_UPDATE. - We pull the session_id from VOICE_STATE_UPDATE.
- We pull the token, endpoint and guild_id from VOICE_SERVER_UPDATE. - We pull the token, endpoint and guild_id from VOICE_SERVER_UPDATE.
@ -202,9 +202,9 @@ class VoiceClient:
The endpoint we are connecting to. The endpoint we are connecting to.
channel : :class:`Channel` channel : :class:`Channel`
The voice channel connected to. The voice channel connected to.
server : :class:`Server` guild : :class:`Guild`
The server the voice channel is connected to. The guild the voice channel is connected to.
Shorthand for ``channel.server``. Shorthand for ``channel.guild``.
loop loop
The event loop that the voice client is running on. The event loop that the voice client is running on.
""" """
@ -229,8 +229,8 @@ class VoiceClient:
warn_nacl = not has_nacl warn_nacl = not has_nacl
@property @property
def server(self): def guild(self):
return self.channel.server return self.channel.guild
def checked_add(self, attr, value, limit): def checked_add(self, attr, value, limit):
val = getattr(self, attr) val = getattr(self, attr)

102
docs/api.rst

@ -102,7 +102,7 @@ to handle it, which defaults to print a traceback and ignore the exception.
.. function:: on_ready() .. function:: on_ready()
Called when the client is done preparing the data received from Discord. Usually after login is successful Called when the client is done preparing the data received from Discord. Usually after login is successful
and the :attr:`Client.servers` and co. are filled up. and the :attr:`Client.guilds` and co. are filled up.
.. warning:: .. warning::
@ -139,7 +139,7 @@ to handle it, which defaults to print a traceback and ignore the exception.
.. function:: on_message(message) .. function:: on_message(message)
Called when a message is created and sent to a server. Called when a message is created and sent to a guild.
:param message: A :class:`Message` of the current message. :param message: A :class:`Message` of the current message.
@ -184,7 +184,7 @@ to handle it, which defaults to print a traceback and ignore the exception.
Called when a message is deleted. If the message is not found in the Called when a message is deleted. If the message is not found in the
:attr:`Client.messages` cache, then these events will not be called. This :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 happens if the message is too old or the client is participating in high
traffic servers. To fix this, increase the ``max_messages`` option of traffic guilds. To fix this, increase the ``max_messages`` option of
:class:`Client`. :class:`Client`.
:param message: A :class:`Message` of the deleted message. :param message: A :class:`Message` of the deleted message.
@ -194,14 +194,14 @@ to handle it, which defaults to print a traceback and ignore the exception.
Called when a message receives an update event. If the message is not found Called when a message receives an update event. If the message is not found
in the :attr:`Client.messages` cache, then these events will not be called. 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 This happens if the message is too old or the client is participating in high
traffic servers. To fix this, increase the ``max_messages`` option of :class:`Client`. traffic guilds. To fix this, increase the ``max_messages`` option of :class:`Client`.
The following non-exhaustive cases trigger this event: The following non-exhaustive cases trigger this event:
- A message has been pinned or unpinned. - A message has been pinned or unpinned.
- The message content has been changed. - The message content has been changed.
- The message has received an embed. - The message has received an embed.
- For performance reasons, the embed server does not do this in a "consistent" manner. - For performance reasons, the embed guild does not do this in a "consistent" manner.
- A call message has received an update to its participants or ending time. - 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. :param before: A :class:`Message` of the previous version of the message.
@ -245,9 +245,9 @@ to handle it, which defaults to print a traceback and ignore the exception.
.. function:: on_channel_delete(channel) .. function:: on_channel_delete(channel)
on_channel_create(channel) on_channel_create(channel)
Called whenever a channel is removed or added from a server. Called whenever a channel is removed or added from a guild.
Note that you can get the server from :attr:`Channel.server`. Note that you can get the guild from :attr:`Channel.guild`.
:func:`on_channel_create` could also pass in a :class:`PrivateChannel` depending :func:`on_channel_create` could also pass in a :class:`PrivateChannel` depending
on the value of :attr:`Channel.is_private`. on the value of :attr:`Channel.is_private`.
@ -263,7 +263,7 @@ to handle it, which defaults to print a traceback and ignore the exception.
.. function:: on_member_join(member) .. function:: on_member_join(member)
on_member_remove(member) on_member_remove(member)
Called when a :class:`Member` leaves or joins a :class:`Server`. Called when a :class:`Member` leaves or joins a :class:`Guild`.
:param member: The :class:`Member` that joined or left. :param member: The :class:`Member` that joined or left.
@ -282,71 +282,71 @@ to handle it, which defaults to print a traceback and ignore the exception.
:param before: The :class:`Member` that updated their profile with the old info. :param before: The :class:`Member` that updated their profile with the old info.
:param after: The :class:`Member` that updated their profile with the updated info. :param after: The :class:`Member` that updated their profile with the updated info.
.. function:: on_server_join(server) .. function:: on_guild_join(guild)
Called when a :class:`Server` is either created by the :class:`Client` or when the Called when a :class:`Guild` is either created by the :class:`Client` or when the
:class:`Client` joins a server. :class:`Client` joins a guild.
:param server: The class:`Server` that was joined. :param guild: The class:`Guild` that was joined.
.. function:: on_server_remove(server) .. function:: on_guild_remove(guild)
Called when a :class:`Server` is removed from the :class:`Client`. Called when a :class:`Guild` is removed from the :class:`Client`.
This happens through, but not limited to, these circumstances: This happens through, but not limited to, these circumstances:
- The client got banned. - The client got banned.
- The client got kicked. - The client got kicked.
- The client left the server. - The client left the guild.
- The client or the server owner deleted the server. - The client or the guild owner deleted the guild.
In order for this event to be invoked then the :class:`Client` must have In order for this event to be invoked then the :class:`Client` must have
been part of the server to begin with. (i.e. it is part of :attr:`Client.servers`) been part of the guild to begin with. (i.e. it is part of :attr:`Client.guilds`)
:param server: The :class:`Server` that got removed. :param guild: The :class:`Guild` that got removed.
.. function:: on_server_update(before, after) .. function:: on_guild_update(before, after)
Called when a :class:`Server` updates, for example: Called when a :class:`Guild` updates, for example:
- Changed name - Changed name
- Changed AFK channel - Changed AFK channel
- Changed AFK timeout - Changed AFK timeout
- etc - etc
:param before: The :class:`Server` prior to being updated. :param before: The :class:`Guild` prior to being updated.
:param after: The :class:`Server` after being updated. :param after: The :class:`Guild` after being updated.
.. function:: on_server_role_create(role) .. function:: on_guild_role_create(role)
on_server_role_delete(role) on_guild_role_delete(role)
Called when a :class:`Server` creates or deletes a new :class:`Role`. Called when a :class:`Guild` creates or deletes a new :class:`Role`.
To get the server it belongs to, use :attr:`Role.server`. To get the guild it belongs to, use :attr:`Role.guild`.
:param role: The :class:`Role` that was created or deleted. :param role: The :class:`Role` that was created or deleted.
.. function:: on_server_role_update(before, after) .. function:: on_guild_role_update(before, after)
Called when a :class:`Role` is changed server-wide. Called when a :class:`Role` is changed guild-wide.
:param before: The :class:`Role` that updated with the old info. :param before: The :class:`Role` that updated with the old info.
:param after: The :class:`Role` that updated with the updated info. :param after: The :class:`Role` that updated with the updated info.
.. function:: on_server_emojis_update(before, after) .. function:: on_guild_emojis_update(before, after)
Called when a :class:`Server` adds or removes :class:`Emoji`. Called when a :class:`Guild` adds or removes :class:`Emoji`.
:param before: A list of :class:`Emoji` before the update. :param before: A list of :class:`Emoji` before the update.
:param after: A list of :class:`Emoji` after the update. :param after: A list of :class:`Emoji` after the update.
.. function:: on_server_available(server) .. function:: on_guild_available(guild)
on_server_unavailable(server) on_guild_unavailable(guild)
Called when a server becomes available or unavailable. The server must have Called when a guild becomes available or unavailable. The guild must have
existed in the :attr:`Client.servers` cache. existed in the :attr:`Client.guilds` cache.
:param server: The :class:`Server` that has changed availability. :param guild: The :class:`Guild` that has changed availability.
.. function:: on_voice_state_update(before, after) .. function:: on_voice_state_update(before, after)
@ -357,24 +357,24 @@ to handle it, which defaults to print a traceback and ignore the exception.
- A member joins a voice room. - A member joins a voice room.
- A member leaves a voice room. - A member leaves a voice room.
- A member is muted or deafened by their own accord. - A member is muted or deafened by their own accord.
- A member is muted or deafened by a server administrator. - A member is muted or deafened by a guild administrator.
:param before: The :class:`Member` whose voice state changed prior to the changes. :param before: The :class:`Member` whose voice state changed prior to the changes.
:param after: The :class:`Member` whose voice state changed after the changes. :param after: The :class:`Member` whose voice state changed after the changes.
.. function:: on_member_ban(member) .. function:: on_member_ban(member)
Called when a :class:`Member` gets banned from a :class:`Server`. Called when a :class:`Member` gets banned from a :class:`Guild`.
You can access the server that the member got banned from via :attr:`Member.server`. You can access the guild that the member got banned from via :attr:`Member.guild`.
:param member: The member that got banned. :param member: The member that got banned.
.. function:: on_member_unban(server, user) .. function:: on_member_unban(guild, user)
Called when a :class:`User` gets unbanned from a :class:`Server`. Called when a :class:`User` gets unbanned from a :class:`Guild`.
:param server: The server the user got unbanned from. :param guild: The guild the user got unbanned from.
:param user: The user that got unbanned. :param user: The user that got unbanned.
.. function:: on_typing(channel, user, when) .. function:: on_typing(channel, user, when)
@ -499,9 +499,9 @@ All enumerations are subclasses of `enum`_.
The system message denoting that a pinned message has been added to a channel. The system message denoting that a pinned message has been added to a channel.
.. class:: ServerRegion .. class:: GuildRegion
Specifies the region a :class:`Server`'s voice server belongs to. Specifies the region a :class:`Guild`'s voice server belongs to.
.. attribute:: us_west .. attribute:: us_west
@ -539,18 +539,18 @@ All enumerations are subclasses of `enum`_.
The Brazil region. The Brazil region.
.. attribute:: vip_us_east .. attribute:: vip_us_east
The US East region for VIP servers. The US East region for VIP guilds.
.. attribute:: vip_us_west .. attribute:: vip_us_west
The US West region for VIP servers. The US West region for VIP guilds.
.. attribute:: vip_amsterdam .. attribute:: vip_amsterdam
The Amsterdam region for VIP servers. The Amsterdam region for VIP guilds.
.. class:: VerificationLevel .. class:: VerificationLevel
Specifies a :class:`Server`\'s verification level, which is the criteria in Specifies a :class:`Guild`\'s verification level, which is the criteria in
which a member must meet before being able to send messages to the server. which a member must meet before being able to send messages to the guild.
.. attribute:: none .. attribute:: none
@ -565,7 +565,7 @@ All enumerations are subclasses of `enum`_.
.. attribute:: high .. attribute:: high
Member must have a verified email, be registered on Discord for more Member must have a verified email, be registered on Discord for more
than five minutes, and be a member of the server itself for more than than five minutes, and be a member of the guild itself for more than
ten minutes. ten minutes.
.. attribute:: table_flip .. attribute:: table_flip
@ -670,10 +670,10 @@ GroupCall
.. autoclass:: GroupCall .. autoclass:: GroupCall
:members: :members:
Server Guild
~~~~~~ ~~~~~~
.. autoclass:: Server .. autoclass:: Guild
:members: :members:
Member Member

Loading…
Cancel
Save