Improve performance of value -> enum by about 5x.
This commit is contained in:
		| @@ -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 | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
| @@ -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): | ||||
|   | ||||
		Reference in New Issue
	
	Block a user