2727
2828import types
2929from collections .abc import Iterator , Mapping
30- from typing import TYPE_CHECKING , Any , ClassVar , NamedTuple , TypeVar
30+ from typing import TYPE_CHECKING , Any , ClassVar , TypeVar
3131
3232from typing_extensions import Self
3333
5353
5454
5555def _create_value_cls (name : str , comparable : bool ) -> type [NewValue ]:
56- class _EnumValue (NamedTuple ):
57- # Denotes an internal marker used to create the value class. The definition
58- # of this must be localized in this function because its methods
59- # are changed multiple times at runtime. This is exposed outside of this
60- # function as a type "NewValue", which denotes the type of the value class.
61- name : str
62- value : Any
63-
64- cls = _EnumValue
65- cls .__name__ = '_EnumValue_' + name
66- cls .__repr__ = lambda self : f'<{ name } .{ self .name } : { self .value !r} >'
67- cls .__str__ = lambda self : f'{ name } .{ self .name } '
68- if comparable :
69- cls .__le__ = lambda self , other : isinstance (other , self .__class__ ) and self .value <= other .value
70- cls .__ge__ = lambda self , other : isinstance (other , self .__class__ ) and self .value >= other .value
71- cls .__lt__ = lambda self , other : isinstance (other , self .__class__ ) and self .value < other .value
72- cls .__gt__ = lambda self , other : isinstance (other , self .__class__ ) and self .value > other .value
73-
74- return cls
75-
76-
77- def _is_descriptor (obj : type [object ]) -> bool :
56+ # All the type ignores here are due to the type checker being unable to recognise
57+ # Runtime type creation without exploding.
58+
59+ class EnumValue :
60+ __slots__ = ("name" , "value" )
61+
62+ def __init__ (self , name : str , value : EnumValue ) -> None :
63+ self .name : str = name
64+ self .value : EnumValue = value
65+
66+ def __repr__ (self ) -> str :
67+ return f'<{ name } .{ self .name } : { self .value !r} >'
68+
69+ def __str__ (self ) -> str :
70+ return f'{ name } .{ self .name } '
71+
72+ if comparable :
73+
74+ def __le__ (self , other : object ) -> bool :
75+ return isinstance (other , self .__class__ ) and self .value <= other .value
76+
77+ def __ge__ (self , other : object ) -> bool :
78+ return isinstance (other , self .__class__ ) and self .value >= other .value
79+
80+ def __lt__ (self , other : object ) -> bool :
81+ return isinstance (other , self .__class__ ) and self .value < other .value
82+
83+ def __gt__ (self , other : object ) -> bool :
84+ return isinstance (other , self .__class__ ) and self .value > other .value
85+
86+ EnumValue .__name__ = '_EnumValue_' + name
87+ return EnumValue
88+
89+
90+ def _is_descriptor (obj : type [object ]):
7891 return hasattr (obj , '__get__' ) or hasattr (obj , '__set__' ) or hasattr (obj , '__delete__' )
7992
8093
8194class EnumMeta (type ):
95+ if TYPE_CHECKING :
96+ _enum_member_names_ : ClassVar [list [str ]]
97+ _enum_member_map_ : ClassVar [dict [str , Any ]]
98+ _enum_value_map_ : ClassVar [dict [Any , Any ]]
99+
82100 def __new__ (
83101 cls ,
84102 name : str ,
@@ -124,29 +142,29 @@ def __new__(
124142 value_cls ._actual_enum_cls_ = actual_cls
125143 return actual_cls
126144
127- def __iter__ (cls : type [ Enum ] ) -> Iterator [Any ]:
145+ def __iter__ (cls ) -> Iterator [Any ]:
128146 return (cls ._enum_member_map_ [name ] for name in cls ._enum_member_names_ )
129147
130- def __reversed__ (cls : type [ Enum ] ) -> Iterator [Any ]:
148+ def __reversed__ (cls ) -> Iterator [Any ]:
131149 return (cls ._enum_member_map_ [name ] for name in reversed (cls ._enum_member_names_ ))
132150
133- def __len__ (cls : type [ Enum ] ) -> int :
151+ def __len__ (cls ) -> int :
134152 return len (cls ._enum_member_names_ )
135153
136154 def __repr__ (cls ) -> str :
137155 return f'<enum { cls .__name__ } >'
138156
139157 @property
140- def __members__ (cls : type [ Enum ] ) -> Mapping [str , Any ]:
158+ def __members__ (cls ) -> Mapping [str , Any ]:
141159 return types .MappingProxyType (cls ._enum_member_map_ )
142160
143- def __call__ (cls : type [ Enum ] , value : str ) -> Any :
161+ def __call__ (cls , value : str ) -> Any :
144162 try :
145163 return cls ._enum_value_map_ [value ]
146164 except (KeyError , TypeError ):
147- raise ValueError (f" { value !r} is not a valid { cls .__name__ } " )
165+ raise ValueError (f' { value !r} is not a valid { cls .__name__ } ' )
148166
149- def __getitem__ (cls : type [ Enum ] , key : str ) -> Any :
167+ def __getitem__ (cls , key : str ) -> Any :
150168 return cls ._enum_member_map_ [key ]
151169
152170 def __setattr__ (cls , name : str , value : Any ) -> None :
@@ -164,21 +182,17 @@ def __instancecheck__(self, instance: Any) -> bool:
164182 return False
165183
166184
167- class Enum (metaclass = EnumMeta ):
168- if TYPE_CHECKING :
169- # Set in the metaclass when __new__ is called. The newly
170- # created cls has these attributes set.
171- _enum_member_names_ : ClassVar [list [str ]]
172- _enum_member_map_ : ClassVar [dict [str , NewValue ]]
173- _enum_value_map_ : ClassVar [dict [OldValue , NewValue ]]
174- _enum_value_cls_ : ClassVar [type [NewValue ]]
185+ if TYPE_CHECKING :
186+ from enum import Enum
187+ else :
175188
176- @classmethod
177- def try_value (cls , value : Any ) -> Any :
178- try :
179- return cls ._enum_value_map_ [value ]
180- except (KeyError , TypeError ):
181- return value
189+ class Enum (metaclass = EnumMeta ):
190+ @classmethod
191+ def try_value (cls , value ):
192+ try :
193+ return cls ._enum_value_map_ [value ]
194+ except (KeyError , TypeError ):
195+ return value
182196
183197
184198class KeyFormat (Enum ):
@@ -580,9 +594,9 @@ def _from_str(cls: type[Self], string: str) -> Self:
580594
581595
582596def create_unknown_value (cls : type [E ], val : Any ) -> NewValue :
583- value_cls = cls ._enum_value_cls_
597+ value_cls = cls ._enum_value_cls_ # type: ignore # This is narrowed below
584598 name = f'UNKNOWN_{ val } '
585- return value_cls (name = name , value = val )
599+ return value_cls (name = name , value = val ) # type: ignore
586600
587601
588602def try_enum (cls : type [E ], val : Any ) -> E :
@@ -591,6 +605,6 @@ def try_enum(cls: type[E], val: Any) -> E:
591605 If it fails it returns a proxy invalid value instead.
592606 """
593607 try :
594- return cls ._enum_value_map_ [val ]
608+ return cls ._enum_value_map_ [val ] # type: ignore # All errors are caught below
595609 except (KeyError , TypeError , AttributeError ):
596610 return create_unknown_value (cls , val )
0 commit comments