Browse Source

Switch IDs to use int instead of str

pull/447/head
Rapptz 9 years ago
parent
commit
45c729b167
  1. 2
      discord/calls.py
  2. 16
      discord/channel.py
  3. 20
      discord/emoji.py
  4. 8
      discord/ext/commands/converter.py
  5. 14
      discord/message.py
  6. 20
      discord/role.py
  7. 39
      discord/server.py
  8. 79
      discord/state.py
  9. 12
      discord/user.py
  10. 13
      discord/utils.py

2
discord/calls.py

@ -112,7 +112,7 @@ class GroupCall:
self.ringing = list(filter(None, map(lambda i: lookup.get(i), kwargs.get('ringing', [])))) self.ringing = list(filter(None, map(lambda i: lookup.get(i), kwargs.get('ringing', []))))
def _update_voice_state(self, data): def _update_voice_state(self, data):
user_id = data['user_id'] user_id = int(data['user_id'])
# left the voice channel? # left the voice channel?
if data['channel_id'] is None: if data['channel_id'] is None:
self._voice_states.pop(user_id, None) self._voice_states.pop(user_id, None)

16
discord/channel.py

@ -58,7 +58,7 @@ class Channel(Hashable):
The channel name. The channel name.
server: :class:`Server` server: :class:`Server`
The server the channel belongs to. The server the channel belongs to.
id: str id: int
The channel ID. The channel ID.
topic: Optional[str] topic: Optional[str]
The channel's topic. None if it doesn't exist. The channel's topic. None if it doesn't exist.
@ -87,6 +87,7 @@ class Channel(Hashable):
def __init__(self, *, state, server, data): def __init__(self, *, state, server, data):
self._state = state self._state = state
self.id = int(data['id'])
self._update(server, data) self._update(server, data)
self.voice_members = [] self.voice_members = []
@ -96,7 +97,6 @@ class Channel(Hashable):
def _update(self, server, data): def _update(self, server, data):
self.server = server self.server = server
self.name = data['name'] self.name = data['name']
self.id = data['id']
self.topic = data.get('topic') self.topic = data.get('topic')
self.position = data['position'] self.position = data['position']
self.bitrate = data.get('bitrate') self.bitrate = data.get('bitrate')
@ -107,8 +107,8 @@ class Channel(Hashable):
everyone_id = self.server.id everyone_id = self.server.id
for index, overridden in enumerate(data.get('permission_overwrites', [])): for index, overridden in enumerate(data.get('permission_overwrites', [])):
overridden_id = overridden['id'] overridden_id = int(overridden.pop('id'))
self._permission_overwrites.append(Overwrites(**overridden)) self._permission_overwrites.append(Overwrites(id=overridden_id, **overridden))
if overridden['type'] == 'member': if overridden['type'] == 'member':
continue continue
@ -336,7 +336,7 @@ class PrivateChannel(Hashable):
The users you are participating with in the private channel. The users you are participating with in the private channel.
me: :class:`User` me: :class:`User`
The user presenting yourself. The user presenting yourself.
id: str id: int
The private channel ID. The private channel ID.
is_private: bool is_private: bool
``True`` if the channel is a private channel (i.e. PM). ``True`` in this case. ``True`` if the channel is a private channel (i.e. PM). ``True`` in this case.
@ -358,13 +358,13 @@ class PrivateChannel(Hashable):
def __init__(self, *, me, state, data): def __init__(self, *, me, state, data):
self._state = state self._state = state
self.recipients = [state.try_insert_user(u) for u in data['recipients']] self.recipients = [state.try_insert_user(u) for u in data['recipients']]
self.id = data['id'] self.id = int(data['id'])
self.me = me self.me = me
self.type = ChannelType(data['type']) self.type = try_enum(ChannelType, data['type'])
self._update_group(data) self._update_group(data)
def _update_group(self, data): def _update_group(self, data):
owner_id = data.get('owner_id') owner_id = utils._get_as_snowflake(data, 'owner_id')
self.icon = data.get('icon') self.icon = data.get('icon')
self.name = data.get('name') self.name = data.get('name')
self.owner = utils.find(lambda u: u.id == owner_id, self.recipients) self.owner = utils.find(lambda u: u.id == owner_id, self.recipients)

20
discord/emoji.py

@ -54,17 +54,17 @@ class Emoji(Hashable):
Attributes Attributes
----------- -----------
name : str name: str
The name of the emoji. The name of the emoji.
id : str id: int
The emoji's ID. The emoji's ID.
require_colons : bool require_colons: bool
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` server: :class:`Server`
The server the emoji belongs to. The server 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.
""" """
@ -76,10 +76,10 @@ class Emoji(Hashable):
self._from_data(data) self._from_data(data)
def _from_data(self, emoji): def _from_data(self, emoji):
self.require_colons = emoji.get('require_colons') self.require_colons = emoji['require_colons']
self.managed = emoji.get('managed') self.managed = emoji['managed']
self.id = emoji.get('id') self.id = int(emoji['id'])
self.name = emoji.get('name') self.name = emoji['name']
self.roles = emoji.get('roles', []) self.roles = emoji.get('roles', [])
if self.roles: if self.roles:
roles = set(self.roles) roles = set(self.roles)

8
discord/ext/commands/converter.py

@ -90,7 +90,7 @@ class MemberConverter(IDConverter):
else: else:
result = _get_from_servers(bot, 'get_member_named', self.argument) result = _get_from_servers(bot, 'get_member_named', self.argument)
else: else:
user_id = match.group(1) user_id = int(match.group(1))
if server: if server:
result = server.get_member(user_id) result = server.get_member(user_id)
else: else:
@ -118,7 +118,7 @@ class ChannelConverter(IDConverter):
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 = match.group(1) channel_id = int(match.group(1))
if server: if server:
result = server.get_channel(channel_id) result = server.get_channel(channel_id)
else: else:
@ -151,7 +151,7 @@ class RoleConverter(IDConverter):
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=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(server.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))
@ -187,7 +187,7 @@ class EmojiConverter(IDConverter):
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)
else: else:
emoji_id = 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 server:

14
discord/message.py

@ -95,9 +95,9 @@ class Message:
role_mentions: list role_mentions: list
A list of :class:`Role` that were mentioned. If the message is in a private message A list of :class:`Role` that were mentioned. If the message is in a private message
then the list is always empty. then the list is always empty.
id: str id: int
The message ID. The message ID.
webhook_id: Optional[str] webhook_id: Optional[int]
If this message was sent by a webhook, then this is the webhook ID's that sent this If this message was sent by a webhook, then this is the webhook ID's that sent this
message. message.
attachments: list attachments: list
@ -163,7 +163,7 @@ class Message:
return return
for mention in mentions: for mention in mentions:
id_search = mention['id'] id_search = int(mention['id'])
member = self.server.get_member(id_search) member = self.server.get_member(id_search)
if member is not None: if member is not None:
self.mentions.append(member) self.mentions.append(member)
@ -185,7 +185,7 @@ class Message:
# the author # the author
participants = [] participants = []
for uid in call.get('participants', []): for uid in map(int, call.get('participants', [])):
if uid == self.author.id: if uid == self.author.id:
participants.append(self.author) participants.append(self.author)
else: else:
@ -204,21 +204,21 @@ class Message:
This allows you receive the user IDs of mentioned users This allows you receive the user IDs of mentioned users
even in a private message context. even in a private message context.
""" """
return re.findall(r'<@!?([0-9]+)>', self.content) return [int(x) for x in re.findall(r'<@!?([0-9]+)>', self.content)]
@utils.cached_slot_property('_cs_raw_channel_mentions') @utils.cached_slot_property('_cs_raw_channel_mentions')
def raw_channel_mentions(self): def raw_channel_mentions(self):
"""A property that returns an array of channel IDs matched with """A property that returns an array of channel IDs matched with
the syntax of <#channel_id> in the message content. the syntax of <#channel_id> in the message content.
""" """
return re.findall(r'<#([0-9]+)>', self.content) return [int(x) for x in re.findall(r'<#([0-9]+)>', self.content)]
@utils.cached_slot_property('_cs_raw_role_mentions') @utils.cached_slot_property('_cs_raw_role_mentions')
def raw_role_mentions(self): def raw_role_mentions(self):
"""A property that returns an array of role IDs matched with """A property that returns an array of role IDs matched with
the syntax of <@&role_id> in the message content. the syntax of <@&role_id> in the message content.
""" """
return re.findall(r'<@&([0-9]+)>', self.content) return [int(x) for x in re.findall(r'<@&([0-9]+)>', self.content)]
@utils.cached_slot_property('_cs_channel_mentions') @utils.cached_slot_property('_cs_channel_mentions')
def channel_mentions(self): def channel_mentions(self):

20
discord/role.py

@ -56,25 +56,25 @@ class Role(Hashable):
Attributes Attributes
---------- ----------
id : str id: int
The ID for the role. The ID for the role.
name : str name: str
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` server: :class:`Server`
The server the role belongs to. The server 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
Indicates if the role will be displayed separately from other members. Indicates if the role will be displayed separately from other members.
position : int position: int
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 server 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.
""" """
@ -84,6 +84,7 @@ class Role(Hashable):
def __init__(self, *, server, state, data): def __init__(self, *, server, state, data):
self.server = server self.server = server
self._state = state self._state = state
self.id = int(data['id'])
self._update(data) self._update(data)
def __str__(self): def __str__(self):
@ -120,7 +121,6 @@ class Role(Hashable):
return not r return not r
def _update(self, data): def _update(self, data):
self.id = data['id']
self.name = data['name'] self.name = data['name']
self.permissions = Permissions(data.get('permissions', 0)) self.permissions = Permissions(data.get('permissions', 0))
self.position = data.get('position', 0) self.position = data.get('position', 0)

39
discord/server.py

@ -76,10 +76,10 @@ class Server(Hashable):
An iterable of :class:`Channel` that are currently on the server. An iterable of :class:`Channel` that are currently on the server.
icon: str icon: str
The server's icon. The server's icon.
id: str id: int
The server's ID. The server's ID.
owner: :class:`Member` owner_id: int
The member who owns the server. The server owner's ID. Use :attr:`Server.owner` instead.
unavailable: bool unavailable: bool
Indicates if the server is unavailable. If this is ``True`` then the Indicates if the server 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:`Server.id` is slim and they might
@ -111,14 +111,13 @@ class Server(Hashable):
""" """
__slots__ = ('afk_timeout', 'afk_channel', '_members', '_channels', 'icon', __slots__ = ('afk_timeout', 'afk_channel', '_members', '_channels', 'icon',
'name', 'id', 'owner', 'unavailable', 'name', 'region', 'name', 'id', 'unavailable', 'name', 'region',
'_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' )
def __init__(self, *, data, state): def __init__(self, *, data, state):
self._channels = {} self._channels = {}
self.owner = None
self._members = {} self._members = {}
self._voice_states = {} self._voice_states = {}
self._state = state self._state = state
@ -158,9 +157,9 @@ class Server(Hashable):
def __str__(self): def __str__(self):
return self.name return self.name
def _update_voice_state(self, data): def _update_voice_state(self, data, channel_id):
user_id = data['user_id'] user_id = int(data['user_id'])
channel = self.get_channel(data['channel_id']) channel = self.get_channel(channel_id)
try: try:
# check if we should remove the voice state from cache # check if we should remove the voice state from cache
if channel is None: if channel is None:
@ -230,7 +229,7 @@ class Server(Hashable):
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 = 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(server=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', [])]
@ -251,22 +250,20 @@ class Server(Hashable):
self._sync(guild) self._sync(guild)
self.large = None if member_count is None else self._member_count >= 250 self.large = None if member_count is None else self._member_count >= 250
if 'owner_id' in guild: self.owner_id = utils._get_as_snowflake(guild, 'owner_id')
self.owner_id = guild['owner_id'] self.afk_channel = self.get_channel(utils._get_as_snowflake(guild, 'afk_channel_id'))
self.owner = self.get_member(self.owner_id)
afk_id = guild.get('afk_channel_id')
self.afk_channel = self.get_channel(afk_id)
for obj in guild.get('voice_states', []): for obj in guild.get('voice_states', []):
self._update_voice_state(obj) self._update_voice_state(obj, int(obj['channel_id']))
def _sync(self, data): def _sync(self, data):
if 'large' in data: try:
self.large = data['large'] self.large = data['large']
except KeyError:
pass
for presence in data.get('presences', []): for presence in data.get('presences', []):
user_id = presence['user']['id'] user_id = int(presence['user']['id'])
member = self.get_member(user_id) member = self.get_member(user_id)
if member is not None: if member is not None:
member.status = try_enum(Status, presence['status']) member.status = try_enum(Status, presence['status'])
@ -279,7 +276,6 @@ class Server(Hashable):
channel = Channel(server=self, data=c, state=self._state) channel = Channel(server=self, data=c, state=self._state)
self._add_channel(channel) self._add_channel(channel)
@utils.cached_slot_property('_default_role') @utils.cached_slot_property('_default_role')
def default_role(self): def default_role(self):
"""Gets the @everyone role that all members have by default.""" """Gets the @everyone role that all members have by default."""
@ -290,6 +286,11 @@ class Server(Hashable):
"""Gets the default :class:`Channel` for the server.""" """Gets the default :class:`Channel` for the server."""
return utils.find(lambda c: c.is_default, self.channels) return utils.find(lambda c: c.is_default, self.channels)
@property
def owner(self):
""":class:`Member`: The member that owns the server."""
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 server's icon. Returns an empty string if it has no icon."""

79
discord/state.py

@ -121,7 +121,7 @@ class ConnectionState:
def try_insert_user(self, data): def try_insert_user(self, data):
# this way is 300% faster than `dict.setdefault`. # this way is 300% faster than `dict.setdefault`.
user_id = data['id'] user_id = int(data['id'])
try: try:
return self._users[user_id] return self._users[user_id]
except KeyError: except KeyError:
@ -237,27 +237,27 @@ class ConnectionState:
self.dispatch('resumed') self.dispatch('resumed')
def parse_message_create(self, data): def parse_message_create(self, data):
channel = self.get_channel(data.get('channel_id')) channel = self.get_channel(int(data['channel_id']))
message = Message(channel=channel, data=data, state=self.ctx) message = Message(channel=channel, data=data, state=self.ctx)
self.dispatch('message', message) self.dispatch('message', message)
self.messages.append(message) self.messages.append(message)
def parse_message_delete(self, data): def parse_message_delete(self, data):
message_id = data.get('id') message_id = int(data['id'])
found = self._get_message(message_id) found = self._get_message(message_id)
if found is not None: if found is not None:
self.dispatch('message_delete', found) self.dispatch('message_delete', found)
self.messages.remove(found) self.messages.remove(found)
def parse_message_delete_bulk(self, data): def parse_message_delete_bulk(self, data):
message_ids = set(data.get('ids', [])) message_ids = set(map(int, data.get('ids', [])))
to_be_deleted = list(filter(lambda m: m.id in message_ids, self.messages)) to_be_deleted = list(filter(lambda m: m.id in message_ids, self.messages))
for msg in to_be_deleted: for msg in to_be_deleted:
self.dispatch('message_delete', msg) self.dispatch('message_delete', msg)
self.messages.remove(msg) self.messages.remove(msg)
def parse_message_update(self, data): def parse_message_update(self, data):
message = self._get_message(data.get('id')) message = self._get_message(int(data['id']))
if message is not None: if message is not None:
older_message = copy.copy(message) older_message = copy.copy(message)
if 'call' in data: if 'call' in data:
@ -323,7 +323,7 @@ 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(data.get('guild_id')) server = self._get_server(utils._get_as_snowflake(data, 'guild_id'))
if server is None: if server is None:
return return
@ -348,7 +348,7 @@ 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(data.get('guild_id')) server = self._get_server(int(data['guild_id']))
if server is not None: if server is not None:
channel_id = data.get('id') channel_id = data.get('id')
channel = server.get_channel(channel_id) channel = server.get_channel(channel_id)
@ -358,7 +358,7 @@ class ConnectionState:
def parse_channel_update(self, data): def parse_channel_update(self, data):
channel_type = try_enum(ChannelType, data.get('type')) channel_type = try_enum(ChannelType, data.get('type'))
channel_id = data.get('id') channel_id = int(data['id'])
if channel_type is ChannelType.group: if channel_type is ChannelType.group:
channel = self._get_private_channel(channel_id) channel = self._get_private_channel(channel_id)
old_channel = copy.copy(channel) old_channel = copy.copy(channel)
@ -366,7 +366,7 @@ class ConnectionState:
self.dispatch('channel_update', old_channel, channel) self.dispatch('channel_update', old_channel, channel)
return return
server = self._get_server(data.get('guild_id')) server = self._get_server(utils._get_as_snowflake(data, 'guild_id'))
if server is not None: if server is not None:
channel = server.get_channel(channel_id) channel = server.get_channel(channel_id)
if channel is not None: if channel is not None:
@ -381,7 +381,7 @@ class ConnectionState:
channel = PrivateChannel(me=self.user, data=data, state=self.ctx) channel = PrivateChannel(me=self.user, data=data, state=self.ctx)
self._add_private_channel(channel) self._add_private_channel(channel)
else: else:
server = self._get_server(data.get('guild_id')) server = self._get_server(utils._get_as_snowflake(data, 'guild_id'))
if server is not None: if server is not None:
channel = Channel(server=server, state=self.ctx, data=data) channel = Channel(server=server, state=self.ctx, data=data)
server._add_channel(channel) server._add_channel(channel)
@ -389,13 +389,13 @@ class ConnectionState:
self.dispatch('channel_create', channel) self.dispatch('channel_create', channel)
def parse_channel_recipient_add(self, data): def parse_channel_recipient_add(self, data):
channel = self._get_private_channel(data.get('channel_id')) channel = self._get_private_channel(int(data['channel_id']))
user = self.try_insert_user(data['user']) user = self.try_insert_user(data['user'])
channel.recipients.append(user) channel.recipients.append(user)
self.dispatch('group_join', channel, user) self.dispatch('group_join', channel, user)
def parse_channel_recipient_remove(self, data): def parse_channel_recipient_remove(self, data):
channel = self._get_private_channel(data.get('channel_id')) channel = self._get_private_channel(int(data['channel_id']))
user = self.try_insert_user(data['user']) user = self.try_insert_user(data['user'])
try: try:
channel.recipients.remove(user) channel.recipients.remove(user)
@ -411,18 +411,18 @@ class ConnectionState:
if role is not None: if role is not None:
roles.append(role) roles.append(role)
data['roles'] = sorted(roles, key=lambda r: int(r.id)) data['roles'] = sorted(roles, key=lambda r: r.id)
return Member(server=server, data=data, state=self.ctx) return Member(server=server, data=data, state=self.ctx)
def parse_guild_member_add(self, data): def parse_guild_member_add(self, data):
server = self._get_server(data.get('guild_id')) server = self._get_server(int(data['guild_id']))
member = self._make_member(server, data) member = self._make_member(server, data)
server._add_member(member) server._add_member(member)
server._member_count += 1 server._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(data.get('guild_id')) server = self._get_server(int(data['guild_id']))
if server is not None: if server is not None:
user_id = data['user']['id'] user_id = data['user']['id']
member = server.get_member(user_id) member = server.get_member(user_id)
@ -443,7 +443,7 @@ 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(data.get('guild_id')) server = self._get_server(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 = server.get_member(user_id)
@ -453,7 +453,7 @@ class ConnectionState:
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(data.get('guild_id')) server = self._get_server(int(data['guild_id']))
before_emojis = server.emojis before_emojis = server.emojis
server.emojis = [Emoji(server=server, data=e, state=self.ctx) for e in data.get('emojis', [])] server.emojis = [Emoji(server=server, data=e, state=self.ctx) for e in data.get('emojis', [])]
self.dispatch('server_emojis_update', before_emojis, server.emojis) self.dispatch('server_emojis_update', before_emojis, server.emojis)
@ -525,18 +525,18 @@ class ConnectionState:
self.dispatch('server_join', server) self.dispatch('server_join', server)
def parse_guild_sync(self, data): def parse_guild_sync(self, data):
server = self._get_server(data.get('id')) server = self._get_server(int(data['id']))
server._sync(data) server._sync(data)
def parse_guild_update(self, data): def parse_guild_update(self, data):
server = self._get_server(data.get('id')) server = self._get_server(int(data['id']))
if server is not None: if server is not None:
old_server = copy.copy(server) old_server = copy.copy(server)
server._from_data(data) server._from_data(data)
self.dispatch('server_update', old_server, server) self.dispatch('server_update', old_server, server)
def parse_guild_delete(self, data): def parse_guild_delete(self, data):
server = self._get_server(data.get('id')) server = self._get_server(int(data['id']))
if server is None: if server is None:
return return
@ -559,7 +559,7 @@ 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(data.get('guild_id')) server = self._get_server(int(data['guild_id']))
if server is not None: if server 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(server.members, id=user_id)
@ -567,21 +567,21 @@ class ConnectionState:
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(data.get('guild_id')) server = self._get_server(int(data['guild_id']))
if server is not None: if server 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', server, user)
def parse_guild_role_create(self, data): def parse_guild_role_create(self, data):
server = self._get_server(data['guild_id']) server = self._get_server(int(data['guild_id']))
role_data = data['role'] role_data = data['role']
role = Role(server=server, data=role_data, state=self.ctx) role = Role(server=server, data=role_data, state=self.ctx)
server._add_role(role) server._add_role(role)
self.dispatch('server_role_create', role) self.dispatch('server_role_create', role)
def parse_guild_role_delete(self, data): def parse_guild_role_delete(self, data):
server = self._get_server(data.get('guild_id')) server = self._get_server(int(data['guild_id']))
if server is not None: if server 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, server.roles)
@ -593,7 +593,7 @@ class ConnectionState:
self.dispatch('server_role_delete', role) self.dispatch('server_role_delete', role)
def parse_guild_role_update(self, data): def parse_guild_role_update(self, data):
server = self._get_server(data.get('guild_id')) server = self._get_server(int(data['guild_id']))
if server is not None: if server is not None:
role_data = data['role'] role_data = data['role']
role_id = role_data['id'] role_id = role_data['id']
@ -604,7 +604,7 @@ class ConnectionState:
self.dispatch('server_role_update', old_role, role) self.dispatch('server_role_update', old_role, role)
def parse_guild_members_chunk(self, data): def parse_guild_members_chunk(self, data):
server = self._get_server(data.get('guild_id')) server = self._get_server(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(server, member)
@ -612,35 +612,32 @@ class ConnectionState:
if existing is None or existing.joined_at is None: if existing is None or existing.joined_at is None:
server._add_member(m) server._add_member(m)
# if the owner is offline, server.owner is potentially None
# therefore we should check if this chunk makes it point to a valid
# member.
server.owner = server.get_member(server.owner_id)
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, server, len(members))
def parse_voice_state_update(self, data): def parse_voice_state_update(self, data):
server = self._get_server(data.get('guild_id')) server = self._get_server(utils._get_as_snowflake(data, 'guild_id'))
channel_id = utils._get_as_snowflake(data, 'channel_id')
if server is not None: if server is not None:
if data.get('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(server.id)
if voice is not None: if voice is not None:
voice.channel = server.get_channel(data.get('channel_id')) voice.channel = server.get_channel(channel_id)
member, before, after = server._update_voice_state(data) member, before, after = server._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:
# in here we're either at private or group calls # in here we're either at private or group calls
call = self._calls.get(data.get('channel_id'), None) call = self._calls.get(channel_id)
if call is not None: if call is not None:
call._update_voice_state(data) call._update_voice_state(data)
def parse_typing_start(self, data): def parse_typing_start(self, data):
channel = self.get_channel(data.get('channel_id')) channel = self.get_channel(int(data['channel_id']))
if channel is not None: if channel is not None:
member = None member = None
user_id = data.get('user_id') user_id = utils._get_as_snowflake(data, 'user_id')
is_private = getattr(channel, 'is_private', None) is_private = getattr(channel, 'is_private', None)
if is_private == None: if is_private == None:
return return
@ -655,21 +652,21 @@ class ConnectionState:
self.dispatch('typing', channel, member, timestamp) self.dispatch('typing', channel, member, timestamp)
def parse_call_create(self, data): def parse_call_create(self, data):
message = self._get_message(data.get('message_id')) message = self._get_message(int(data['message_id']))
if message is not None: if message is not None:
call = GroupCall(call=message, **data) call = GroupCall(call=message, **data)
self._calls[data['channel_id']] = call self._calls[int(data['channel_id'])] = call
self.dispatch('call', call) self.dispatch('call', call)
def parse_call_update(self, data): def parse_call_update(self, data):
call = self._calls.get(data.get('channel_id'), None) call = self._calls.get(int(data['channel_id']))
if call is not None: if call is not None:
before = copy.copy(call) before = copy.copy(call)
call._update(**data) call._update(**data)
self.dispatch('call_update', before, call) self.dispatch('call_update', before, call)
def parse_call_delete(self, data): def parse_call_delete(self, data):
call = self._calls.pop(data.get('channel_id'), None) call = self._calls.pop(int(data['channel_id']), None)
if call is not None: if call is not None:
self.dispatch('call_remove', call) self.dispatch('call_remove', call)

12
discord/user.py

@ -46,15 +46,15 @@ class User:
Attributes Attributes
----------- -----------
name : str name: str
The user's username. The user's username.
id : str id: int
The user's unique ID. The user's unique ID.
discriminator : str or int discriminator: str
The user's discriminator. This is given when the username has conflicts. The user's discriminator. This is given when the username has conflicts.
avatar : str avatar: str
The avatar hash the user has. Could be None. The avatar hash the user has. Could be None.
bot : bool bot: bool
Specifies if the user is a bot account. Specifies if the user is a bot account.
""" """
@ -63,7 +63,7 @@ class User:
def __init__(self, *, state, data): def __init__(self, *, state, data):
self._state = state self._state = state
self.name = data['username'] self.name = data['username']
self.id = data['id'] self.id = int(data['id'])
self.discriminator = data['discriminator'] self.discriminator = data['discriminator']
self.avatar = data['avatar'] self.avatar = data['avatar']
self.bot = data.get('bot', False) self.bot = data.get('bot', False)

13
discord/utils.py

@ -120,7 +120,7 @@ def oauth_url(client_id, permissions=None, server=None, redirect_uri=None):
def snowflake_time(id): def snowflake_time(id):
"""Returns the creation date in UTC of a discord id.""" """Returns the creation date in UTC of a discord id."""
return datetime.datetime.utcfromtimestamp(((int(id) >> 22) + DISCORD_EPOCH) / 1000) return datetime.datetime.utcfromtimestamp(((id >> 22) + DISCORD_EPOCH) / 1000)
def time_snowflake(datetime_obj, high=False): def time_snowflake(datetime_obj, high=False):
"""Returns a numeric snowflake pretending to be created at the given date. """Returns a numeric snowflake pretending to be created at the given date.
@ -231,8 +231,15 @@ def _unique(iterable):
adder = seen.add adder = seen.add
return [x for x in iterable if not (x in seen or adder(x))] return [x for x in iterable if not (x in seen or adder(x))]
def _null_event(*args, **kwargs): def _get_as_snowflake(data, key):
pass try:
value = data[key]
except KeyError:
return None
else:
if value is None:
return value
return int(value)
def _get_mime_type_for_image(data): def _get_mime_type_for_image(data):
if data.startswith(b'\x89\x50\x4E\x47\x0D\x0A\x1A\x0A'): if data.startswith(b'\x89\x50\x4E\x47\x0D\x0A\x1A\x0A'):

Loading…
Cancel
Save