aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRapptz <[email protected]>2019-04-15 21:30:47 -0400
committerRapptz <[email protected]>2019-04-15 21:30:47 -0400
commit6f26a4aad8e223046d5627bd266cc49a68bbe943 (patch)
tree8e78783196ead4cd967b150e356009e30afd0282
parent[tasks] Fix assignment of tuple when appending (diff)
downloaddiscord.py-6f26a4aad8e223046d5627bd266cc49a68bbe943.tar.xz
discord.py-6f26a4aad8e223046d5627bd266cc49a68bbe943.zip
Improve performance of value -> enum by about 5x.
-rw-r--r--discord/audit_logs.py2
-rw-r--r--discord/enums.py57
-rw-r--r--discord/user.py2
3 files changed, 57 insertions, 4 deletions
diff --git a/discord/audit_logs.py b/discord/audit_logs.py
index faf05f20..49a5bb5a 100644
--- a/discord/audit_logs.py
+++ b/discord/audit_logs.py
@@ -216,7 +216,7 @@ class AuditLogEntry:
self._from_data(data)
def _from_data(self, data):
- self.action = enums.AuditLogAction(data['action_type'])
+ self.action = enums.try_enum(enums.AuditLogAction, data['action_type'])
self.id = int(data['id'])
# this key is technically not usually present
diff --git a/discord/enums.py b/discord/enums.py
index ff5266fa..4c59dbf9 100644
--- a/discord/enums.py
+++ b/discord/enums.py
@@ -32,6 +32,20 @@ __all__ = ['ChannelType', 'MessageType', 'VoiceRegion', 'SpeakingState',
'UserFlags', 'ActivityType', 'HypeSquadHouse', 'NotificationLevel',
'PremiumType', 'UserContentFilter', 'FriendFlags', 'Theme']
+def fast_lookup(cls):
+ # NOTE: implies hashable
+ try:
+ lookup = cls._value2member_map_
+ except AttributeError:
+ lookup = {
+ member.value: member
+ for member in cls.__members__
+ }
+ finally:
+ cls.__fast_value_lookup__ = lookup
+ return cls
+
+@fast_lookup
class ChannelType(Enum):
text = 0
private = 1
@@ -44,6 +58,7 @@ class ChannelType(Enum):
def __str__(self):
return self.name
+@fast_lookup
class MessageType(Enum):
default = 0
recipient_add = 1
@@ -54,6 +69,7 @@ class MessageType(Enum):
pins_add = 6
new_member = 7
+@fast_lookup
class VoiceRegion(Enum):
us_west = 'us-west'
us_east = 'us-east'
@@ -78,6 +94,7 @@ class VoiceRegion(Enum):
def __str__(self):
return self.value
+@fast_lookup
class SpeakingState(Enum):
none = 0
voice = 1
@@ -90,6 +107,7 @@ class SpeakingState(Enum):
def __int__(self):
return self.value
+@fast_lookup
class VerificationLevel(Enum):
none = 0
low = 1
@@ -102,6 +120,7 @@ class VerificationLevel(Enum):
def __str__(self):
return self.name
+@fast_lookup
class ContentFilter(Enum):
disabled = 0
no_role = 1
@@ -110,11 +129,13 @@ class ContentFilter(Enum):
def __str__(self):
return self.name
+@fast_lookup
class UserContentFilter(Enum):
disabled = 0
friends = 1
all_messages = 2
+@fast_lookup
class FriendFlags(Enum):
noone = 0
mutual_guilds = 1
@@ -122,10 +143,12 @@ class FriendFlags(Enum):
guild_and_friends = 3
everyone = 4
+@fast_lookup
class Theme(Enum):
light = 'light'
dark = 'dark'
+@fast_lookup
class Status(Enum):
online = 'online'
offline = 'offline'
@@ -137,6 +160,7 @@ class Status(Enum):
def __str__(self):
return self.value
+@fast_lookup
class DefaultAvatar(Enum):
blurple = 0
grey = 1
@@ -148,21 +172,25 @@ class DefaultAvatar(Enum):
def __str__(self):
return self.name
+@fast_lookup
class RelationshipType(Enum):
friend = 1
blocked = 2
incoming_request = 3
outgoing_request = 4
+@fast_lookup
class NotificationLevel(Enum):
all_messages = 0
only_mentions = 1
+@fast_lookup
class AuditLogActionCategory(Enum):
create = 1
delete = 2
update = 3
+@fast_lookup
class AuditLogAction(Enum):
guild_update = 1
channel_create = 10
@@ -245,6 +273,7 @@ class AuditLogAction(Enum):
elif v < 80:
return 'message'
+@fast_lookup
class UserFlags(Enum):
staff = 1
partner = 2
@@ -255,6 +284,7 @@ class UserFlags(Enum):
hypesquad_balance = 256
early_supporter = 512
+@fast_lookup
class ActivityType(Enum):
unknown = -1
playing = 0
@@ -262,11 +292,13 @@ class ActivityType(Enum):
listening = 2
watching = 3
+@fast_lookup
class HypeSquadHouse(Enum):
bravery = 1
brilliance = 2
balance = 3
+@fast_lookup
class PremiumType(Enum):
nitro_classic = 1
nitro = 2
@@ -276,7 +308,28 @@ def try_enum(cls, val):
If it fails it returns the value instead.
"""
+
+ # For some ungodly reason, `cls(x)` is *really* slow
+ # For most use cases it's about 750ns per call
+ # Internally this is dispatched like follows:
+ # cls(x)
+ # cls.__new__(cls, x)
+ # cls._value2member_map[x]
+ # if above fails ^
+ # find it in cls._member_map.items()
+
+ # Accessing the _value2member_map directly gives the biggest
+ # boost to performance, from 750ns to 130ns
+
+ # Now, the weird thing is that regular dict access is approx 31ns
+ # So there's a slowdown in the attribute access somewhere in the
+ # __getattr__ chain that I can't do much about
+
+ # Since this relies on internals the enums have an internal shim
+ # decorator that defines an alias for my own purposes or creates
+ # it for me under __fast_value_lookup__
+
try:
- return cls(val)
- except ValueError:
+ return cls.__fast_value_lookup__[val]
+ except (KeyError, AttributeError):
return val
diff --git a/discord/user.py b/discord/user.py
index 2b0b5263..b1d34868 100644
--- a/discord/user.py
+++ b/discord/user.py
@@ -164,7 +164,7 @@ class BaseUser(_BaseUser):
@property
def default_avatar(self):
"""Returns the default avatar for a given user. This is calculated by the user's discriminator"""
- return DefaultAvatar(int(self.discriminator) % len(DefaultAvatar))
+ return try_enum(DefaultAvatar, int(self.discriminator) % len(DefaultAvatar))
@property
def default_avatar_url(self):