From da95141b8fcab58deb8fa7316f90da28b9dfd9a5 Mon Sep 17 00:00:00 2001 From: Andrei Date: Tue, 11 Oct 2016 03:03:38 -0500 Subject: [PATCH] More __slots__ where it counts --- disco/gateway/events.py | 6 ++++-- disco/state.py | 5 ++++- disco/types/base.py | 15 ++++++++++----- disco/types/channel.py | 16 +++++++++++----- disco/types/guild.py | 41 +++++++++++++++-------------------------- disco/types/invite.py | 4 ++-- disco/types/message.py | 8 ++++---- disco/types/user.py | 16 +++++----------- disco/types/voice.py | 16 ++++++---------- 9 files changed, 61 insertions(+), 66 deletions(-) diff --git a/disco/gateway/events.py b/disco/gateway/events.py index a31b027..67921b0 100644 --- a/disco/gateway/events.py +++ b/disco/gateway/events.py @@ -92,6 +92,7 @@ def wraps_model(model, alias=None): def deco(cls): cls._fields[alias] = Field(model) cls._fields[alias].set_name(alias) + cls.__slots__ = cls.__slots__ + (alias, ) cls._wraps_model = (alias, model) return cls return deco @@ -247,11 +248,12 @@ class GuildRoleUpdate(GuildRoleCreate): pass -class GuildRoleDelete(GuildRoleCreate): +class GuildRoleDelete(GatewayEvent): """ Sent when a role is deleted. """ - pass + guild_id = Field(snowflake) + role_id = Field(snowflake) @wraps_model(Message) diff --git a/disco/state.py b/disco/state.py index 442ae76..5780e96 100644 --- a/disco/state.py +++ b/disco/state.py @@ -276,7 +276,10 @@ class State(object): if event.guild_id not in self.guilds: return - del self.guilds[event.guild_id].roles[event.role.id] + if event.role_id not in self.guilds[event.guild_id].roles: + return + + del self.guilds[event.guild_id].roles[event.role_id] def on_presence_update(self, event): if event.user.id in self.users: diff --git a/disco/types/base.py b/disco/types/base.py index b271ddb..9e59581 100644 --- a/disco/types/base.py +++ b/disco/types/base.py @@ -5,6 +5,8 @@ import functools from holster.enum import BaseEnumMeta from datetime import datetime as real_datetime +from disco.util.functional import CachedSlotProperty + DATETIME_FORMATS = [ '%Y-%m-%dT%H:%M:%S.%f', '%Y-%m-%dT%H:%M:%S' @@ -24,6 +26,8 @@ class FieldType(object): self.typ = typ elif isinstance(typ, BaseEnumMeta): self.typ = lambda raw, _: typ.get(raw) + elif typ is None: + self.typ = lambda x, y: None else: self.typ = lambda raw, _: typ(raw) @@ -192,11 +196,12 @@ class ModelMeta(type): dct = {k: v for k, v in six.iteritems(dct) if k not in fields} - if SlottedModel in parents and '__slots__' not in dct: - dct['__slots__'] = tuple(fields.keys()) - elif '__slots__' in dct and Model in parents and SlottedModel: - dct['__slots__'] = tuple(dct['__slots__']) - parents = tuple([SlottedModel] + [i for i in parents if i != Model]) + if SlottedModel and any(map(lambda k: issubclass(k, SlottedModel), parents)): + bases = set(k for k, v in six.iteritems(dct) if isinstance(v, CachedSlotProperty)) + if '__slots__' in dct: + dct['__slots__'] = tuple(set(dct['__slots__']) | set(fields.keys()) | bases) + else: + dct['__slots__'] = tuple(fields.keys()) + tuple(bases) dct['_fields'] = fields return super(ModelMeta, cls).__new__(cls, name, parents, dct) diff --git a/disco/types/channel.py b/disco/types/channel.py index 7d5cffe..d341783 100644 --- a/disco/types/channel.py +++ b/disco/types/channel.py @@ -5,7 +5,7 @@ from holster.enum import Enum from disco.util.snowflake import to_snowflake from disco.util.functional import cached_property, one_or_many, chunks from disco.types.user import User -from disco.types.base import Model, Field, snowflake, enum, listof, dictof, text +from disco.types.base import SlottedModel, Field, snowflake, enum, listof, dictof, text from disco.types.permissions import Permissions, Permissible, PermissionValue from disco.voice.client import VoiceClient @@ -23,7 +23,15 @@ PermissionOverwriteType = Enum( ) -class PermissionOverwrite(Model): +class ChannelSubType(SlottedModel): + channel_id = Field(None) + + @cached_property + def channel(self): + return self.client.state.channels.get(self.channel_id) + + +class PermissionOverwrite(ChannelSubType): """ A PermissionOverwrite for a :class:`Channel` @@ -39,8 +47,6 @@ class PermissionOverwrite(Model): denied : :class:`PermissionValue` All denied permissions """ - __slots__ = ['id', 'type', 'allow', 'deny', 'channel', 'channel_id'] - id = Field(snowflake) type = Field(enum(PermissionOverwriteType)) allow = Field(PermissionValue) @@ -53,7 +59,7 @@ class PermissionOverwrite(Model): return self.channel.delete_overwrite(self) -class Channel(Model, Permissible): +class Channel(SlottedModel, Permissible): """ Represents a Discord Channel diff --git a/disco/types/guild.py b/disco/types/guild.py index 1f3d745..509860a 100644 --- a/disco/types/guild.py +++ b/disco/types/guild.py @@ -6,7 +6,7 @@ from disco.gateway.packets import OPCode from disco.api.http import APIException from disco.util.snowflake import to_snowflake from disco.util.functional import cached_property -from disco.types.base import Model, Field, snowflake, listof, dictof, lazy_datetime, text, binary, enum +from disco.types.base import SlottedModel, Field, snowflake, listof, dictof, lazy_datetime, text, binary, enum from disco.types.user import User from disco.types.voice import VoiceState from disco.types.channel import Channel @@ -22,7 +22,15 @@ VerificationLevel = Enum( ) -class Emoji(Model): +class GuildSubType(SlottedModel): + guild_id = Field(None) + + @cached_property + def guild(self): + return self.client.state.guilds.get(self.guild_id) + + +class Emoji(GuildSubType): """ An emoji object @@ -39,8 +47,6 @@ class Emoji(Model): roles : list(snowflake) Roles this emoji is attached to. """ - __slots__ = ['id', 'name', 'require_colons', 'managed', 'roles', 'guild', 'guild_id'] - id = Field(snowflake) name = Field(text) require_colons = Field(bool) @@ -48,7 +54,7 @@ class Emoji(Model): roles = Field(listof(snowflake)) -class Role(Model): +class Role(GuildSubType): """ A role object @@ -69,11 +75,6 @@ class Role(Model): position : int The position of this role in the hierarchy. """ - __slots__ = [ - 'id', 'name', 'hoist', 'managed', 'color', 'permissions', 'position', 'mentionable', - 'guild', 'guild_id' - ] - id = Field(snowflake) name = Field(text) hoist = Field(bool) @@ -90,12 +91,8 @@ class Role(Model): def mention(self): return '<@{}>'.format(self.id) - @cached_property - def guild(self): - return self.client.state.guilds.get(self.id) - -class GuildMember(Model): +class GuildMember(GuildSubType): """ A GuildMember object @@ -116,10 +113,6 @@ class GuildMember(Model): roles : list(snowflake) Roles this member is part of. """ - __slots__ = [ - 'user', 'guild_id', 'nick', 'mute', 'deaf', 'joined_at', 'roles', 'guild' - ] - user = Field(User) guild_id = Field(snowflake) nick = Field(text) @@ -170,21 +163,17 @@ class GuildMember(Model): roles = self.roles + [role.id] self.client.api.guilds_members_modify(self.guild.id, self.user.id, roles=roles) - @property + @cached_property def owner(self): return self.guild.owner_id == self.id - @property + @cached_property def mention(self): if self.nick: return '<@!{}>'.format(self.id) return self.user.mention @cached_property - def guild(self): - return self.client.state.guilds.get(self.guild_id) - - @property def id(self): """ Alias to the guild members user id @@ -192,7 +181,7 @@ class GuildMember(Model): return self.user.id -class Guild(Model, Permissible): +class Guild(SlottedModel, Permissible): """ A guild object diff --git a/disco/types/invite.py b/disco/types/invite.py index 709f668..34c5312 100644 --- a/disco/types/invite.py +++ b/disco/types/invite.py @@ -1,10 +1,10 @@ -from disco.types.base import Model, Field, lazy_datetime +from disco.types.base import SlottedModel, Field, lazy_datetime from disco.types.user import User from disco.types.guild import Guild from disco.types.channel import Channel -class Invite(Model): +class Invite(SlottedModel): """ An invite object diff --git a/disco/types/message.py b/disco/types/message.py index 8548867..112f662 100644 --- a/disco/types/message.py +++ b/disco/types/message.py @@ -2,7 +2,7 @@ import re from holster.enum import Enum -from disco.types.base import Model, Field, snowflake, text, lazy_datetime, dictof, listof, enum +from disco.types.base import SlottedModel, Field, snowflake, text, lazy_datetime, dictof, listof, enum from disco.util.snowflake import to_snowflake from disco.util.functional import cached_property from disco.types.user import User @@ -19,7 +19,7 @@ MessageType = Enum( ) -class MessageEmbed(Model): +class MessageEmbed(SlottedModel): """ Message embed object @@ -40,7 +40,7 @@ class MessageEmbed(Model): url = Field(str) -class MessageAttachment(Model): +class MessageAttachment(SlottedModel): """ Message attachment object @@ -70,7 +70,7 @@ class MessageAttachment(Model): width = Field(int) -class Message(Model): +class Message(SlottedModel): """ Represents a Message created within a Channel on Discord. diff --git a/disco/types/user.py b/disco/types/user.py index 8bb4a0c..3e3fc9b 100644 --- a/disco/types/user.py +++ b/disco/types/user.py @@ -1,11 +1,9 @@ from holster.enum import Enum -from disco.types.base import Model, Field, snowflake, text, binary, with_equality, with_hash +from disco.types.base import SlottedModel, Field, snowflake, text, binary, with_equality, with_hash -class User(Model, with_equality('id'), with_hash('id')): - __slots__ = ['id', 'username', 'discriminator', 'avatar', 'verified', 'email', 'presence'] - +class User(SlottedModel, with_equality('id'), with_hash('id')): id = Field(snowflake) username = Field(text) discriminator = Field(str) @@ -13,7 +11,7 @@ class User(Model, with_equality('id'), with_hash('id')): verified = Field(bool) email = Field(str) - presence = None + presence = Field(None) @property def mention(self): @@ -43,17 +41,13 @@ Status = Enum( ) -class Game(Model): - __slots__ = ['type', 'name', 'url'] - +class Game(SlottedModel): type = Field(GameType) name = Field(text) url = Field(text) -class Presence(Model): - __slots__ = ['user', 'game', 'status'] - +class Presence(SlottedModel): user = Field(User) game = Field(Game) status = Field(Status) diff --git a/disco/types/voice.py b/disco/types/voice.py index 84cb092..1647eb3 100644 --- a/disco/types/voice.py +++ b/disco/types/voice.py @@ -1,7 +1,8 @@ -from disco.types.base import Model, Field, snowflake +from disco.types.base import SlottedModel, Field, snowflake +from disco.util.functional import cached_property -class VoiceState(Model): +class VoiceState(SlottedModel): session_id = Field(str) guild_id = Field(snowflake) channel_id = Field(snowflake) @@ -12,19 +13,14 @@ class VoiceState(Model): self_mute = Field(bool) suppress = Field(bool) - __slots__ = [ - 'session_id', 'guild_id', 'channel_id', 'user_id', 'deaf', 'mute', 'self_deaf', - 'self_mute', 'suppress' - ] - - @property + @cached_property def guild(self): return self.client.state.guilds.get(self.guild_id) - @property + @cached_property def channel(self): return self.client.state.channels.get(self.channel_id) - @property + @cached_property def user(self): return self.client.state.users.get(self.user_id)