@ -24,9 +24,13 @@ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE .
DEALINGS IN THE SOFTWARE .
"""
"""
from enum import Enum
import types
import inspect
from collections import namedtuple
from operator import attrgetter
__all__ = (
__all__ = (
' Enum ' ,
' ChannelType ' ,
' ChannelType ' ,
' MessageType ' ,
' MessageType ' ,
' VoiceRegion ' ,
' VoiceRegion ' ,
@ -48,20 +52,88 @@ __all__ = (
' Theme ' ,
' Theme ' ,
)
)
def fast_lookup ( cls ) :
def _create_value_cls ( name ) :
# NOTE: implies hashable
cls = namedtuple ( ' _EnumValue_ ' + name , ' name value ' )
try :
cls . __repr__ = lambda self : ' < %s . %s : %r > ' % ( name , self . name , self . value )
lookup = cls . _value2member_map_
cls . __str__ = lambda self : ' %s . %s ' % ( name , self . name )
except AttributeError :
return cls
lookup = {
member . value : member
class EnumMeta ( type ) :
for member in cls . __members__
def __new__ ( cls , name , bases , attrs ) :
}
value_mapping = { }
finally :
member_mapping = { }
cls . __fast_value_lookup__ = lookup
member_names = [ ]
return cls
value_cls = _create_value_cls ( name )
for key , value in list ( attrs . items ( ) ) :
is_function = isinstance ( value , types . FunctionType )
if key [ 0 ] == ' _ ' and not is_function :
continue
if is_function :
setattr ( value_cls , key , value )
del attrs [ key ]
continue
if inspect . ismethoddescriptor ( value ) :
continue
try :
new_value = value_mapping [ value ]
except KeyError :
new_value = value_cls ( name = key , value = value )
value_mapping [ value ] = new_value
member_names . append ( key )
member_mapping [ key ] = new_value
attrs [ key ] = new_value
attrs [ ' _enum_value_map_ ' ] = value_mapping
attrs [ ' _enum_member_map_ ' ] = member_mapping
attrs [ ' _enum_member_names_ ' ] = member_names
actual_cls = super ( ) . __new__ ( cls , name , bases , attrs )
value_cls . _actual_enum_cls_ = actual_cls
return actual_cls
def __iter__ ( cls ) :
return ( cls . _enum_member_map_ [ name ] for name in cls . _enum_member_names_ )
def __repr__ ( cls ) :
return ' <enum %r > ' % cls . __name__
@property
def __members__ ( cls ) :
return types . MappingProxyType ( cls . _enum_member_map_ )
def __call__ ( cls , value ) :
try :
return cls . _enum_value_map_ [ value ]
except ( KeyError , TypeError ) :
raise ValueError ( " %r is not a valid %s " % ( value , cls . __name__ ) )
def __getitem__ ( cls , key ) :
return cls . _enum_member_map_ [ key ]
def __setattr__ ( cls , name , value ) :
raise TypeError ( ' Enums are immutable. ' )
def __instancecheck__ ( self , instance ) :
# isinstance(x, Y)
# -> __instancecheck__(Y, x)
try :
return instance . _actual_enum_cls_ is self
except AttributeError :
return False
class Enum ( metaclass = EnumMeta ) :
@classmethod
def try_value ( cls , value ) :
try :
return cls . _enum_value_map_ [ value ]
except ( KeyError , TypeError ) :
return value
@fast_lookup
class ChannelType ( Enum ) :
class ChannelType ( Enum ) :
text = 0
text = 0
private = 1
private = 1
@ -74,7 +146,6 @@ class ChannelType(Enum):
def __str__ ( self ) :
def __str__ ( self ) :
return self . name
return self . name
@fast_lookup
class MessageType ( Enum ) :
class MessageType ( Enum ) :
default = 0
default = 0
recipient_add = 1
recipient_add = 1
@ -89,7 +160,6 @@ class MessageType(Enum):
premium_guild_tier_2 = 10
premium_guild_tier_2 = 10
premium_guild_tier_3 = 11
premium_guild_tier_3 = 11
@fast_lookup
class VoiceRegion ( Enum ) :
class VoiceRegion ( Enum ) :
us_west = ' us-west '
us_west = ' us-west '
us_east = ' us-east '
us_east = ' us-east '
@ -115,7 +185,6 @@ class VoiceRegion(Enum):
def __str__ ( self ) :
def __str__ ( self ) :
return self . value
return self . value
@fast_lookup
class SpeakingState ( Enum ) :
class SpeakingState ( Enum ) :
none = 0
none = 0
voice = 1
voice = 1
@ -128,7 +197,6 @@ class SpeakingState(Enum):
def __int__ ( self ) :
def __int__ ( self ) :
return self . value
return self . value
@fast_lookup
class VerificationLevel ( Enum ) :
class VerificationLevel ( Enum ) :
none = 0
none = 0
low = 1
low = 1
@ -141,7 +209,6 @@ class VerificationLevel(Enum):
def __str__ ( self ) :
def __str__ ( self ) :
return self . name
return self . name
@fast_lookup
class ContentFilter ( Enum ) :
class ContentFilter ( Enum ) :
disabled = 0
disabled = 0
no_role = 1
no_role = 1
@ -150,13 +217,11 @@ class ContentFilter(Enum):
def __str__ ( self ) :
def __str__ ( self ) :
return self . name
return self . name
@fast_lookup
class UserContentFilter ( Enum ) :
class UserContentFilter ( Enum ) :
disabled = 0
disabled = 0
friends = 1
friends = 1
all_messages = 2
all_messages = 2
@fast_lookup
class FriendFlags ( Enum ) :
class FriendFlags ( Enum ) :
noone = 0
noone = 0
mutual_guilds = 1
mutual_guilds = 1
@ -164,12 +229,10 @@ class FriendFlags(Enum):
guild_and_friends = 3
guild_and_friends = 3
everyone = 4
everyone = 4
@fast_lookup
class Theme ( Enum ) :
class Theme ( Enum ) :
light = ' light '
light = ' light '
dark = ' dark '
dark = ' dark '
@fast_lookup
class Status ( Enum ) :
class Status ( Enum ) :
online = ' online '
online = ' online '
offline = ' offline '
offline = ' offline '
@ -181,7 +244,6 @@ class Status(Enum):
def __str__ ( self ) :
def __str__ ( self ) :
return self . value
return self . value
@fast_lookup
class DefaultAvatar ( Enum ) :
class DefaultAvatar ( Enum ) :
blurple = 0
blurple = 0
grey = 1
grey = 1
@ -193,25 +255,21 @@ class DefaultAvatar(Enum):
def __str__ ( self ) :
def __str__ ( self ) :
return self . name
return self . name
@fast_lookup
class RelationshipType ( Enum ) :
class RelationshipType ( Enum ) :
friend = 1
friend = 1
blocked = 2
blocked = 2
incoming_request = 3
incoming_request = 3
outgoing_request = 4
outgoing_request = 4
@fast_lookup
class NotificationLevel ( Enum ) :
class NotificationLevel ( Enum ) :
all_messages = 0
all_messages = 0
only_mentions = 1
only_mentions = 1
@fast_lookup
class AuditLogActionCategory ( Enum ) :
class AuditLogActionCategory ( Enum ) :
create = 1
create = 1
delete = 2
delete = 2
update = 3
update = 3
@fast_lookup
class AuditLogAction ( Enum ) :
class AuditLogAction ( Enum ) :
guild_update = 1
guild_update = 1
channel_create = 10
channel_create = 10
@ -294,7 +352,6 @@ class AuditLogAction(Enum):
elif v < 80 :
elif v < 80 :
return ' message '
return ' message '
@fast_lookup
class UserFlags ( Enum ) :
class UserFlags ( Enum ) :
staff = 1
staff = 1
partner = 2
partner = 2
@ -305,7 +362,6 @@ class UserFlags(Enum):
hypesquad_balance = 256
hypesquad_balance = 256
early_supporter = 512
early_supporter = 512
@fast_lookup
class ActivityType ( Enum ) :
class ActivityType ( Enum ) :
unknown = - 1
unknown = - 1
playing = 0
playing = 0
@ -313,13 +369,11 @@ class ActivityType(Enum):
listening = 2
listening = 2
watching = 3
watching = 3
@fast_lookup
class HypeSquadHouse ( Enum ) :
class HypeSquadHouse ( Enum ) :
bravery = 1
bravery = 1
brilliance = 2
brilliance = 2
balance = 3
balance = 3
@fast_lookup
class PremiumType ( Enum ) :
class PremiumType ( Enum ) :
nitro_classic = 1
nitro_classic = 1
nitro = 2
nitro = 2
@ -330,27 +384,7 @@ def try_enum(cls, val):
If it fails it returns the value instead .
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 :
try :
return cls . __fast_value_lookup_ _ [ val ]
return cls . _enum_value_map_ [ val ]
except ( KeyError , AttributeError ) :
except ( KeyError , TypeError , AttributeError ) :
return val
return val