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
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
7588
7689
7790def _is_descriptor (obj : type [object ]) -> bool :
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 , NewValue ]]
98+ _enum_value_map_ : ClassVar [dict [OldValue , NewValue ]]
99+ _enum_value_cls_ : ClassVar [type [NewValue ]]
100+
82101 def __new__ (
83102 cls ,
84103 name : str ,
@@ -124,29 +143,29 @@ def __new__(
124143 value_cls ._actual_enum_cls_ = actual_cls
125144 return actual_cls
126145
127- def __iter__ (cls : type [ Enum ] ) -> Iterator [Any ]:
146+ def __iter__ (cls ) -> Iterator [Any ]:
128147 return (cls ._enum_member_map_ [name ] for name in cls ._enum_member_names_ )
129148
130- def __reversed__ (cls : type [ Enum ] ) -> Iterator [Any ]:
149+ def __reversed__ (cls ) -> Iterator [Any ]:
131150 return (cls ._enum_member_map_ [name ] for name in reversed (cls ._enum_member_names_ ))
132151
133- def __len__ (cls : type [ Enum ] ) -> int :
152+ def __len__ (cls ) -> int :
134153 return len (cls ._enum_member_names_ )
135154
136155 def __repr__ (cls ) -> str :
137156 return f'<enum { cls .__name__ } >'
138157
139158 @property
140- def __members__ (cls : type [ Enum ] ) -> Mapping [str , Any ]:
159+ def __members__ (cls ) -> Mapping [str , Any ]:
141160 return types .MappingProxyType (cls ._enum_member_map_ )
142161
143- def __call__ (cls : type [ Enum ] , value : str ) -> Any :
162+ def __call__ (cls , value : str ) -> Any :
144163 try :
145164 return cls ._enum_value_map_ [value ]
146165 except (KeyError , TypeError ):
147- raise ValueError (f" { value !r} is not a valid { cls .__name__ } " )
166+ raise ValueError (f' { value !r} is not a valid { cls .__name__ } ' )
148167
149- def __getitem__ (cls : type [ Enum ] , key : str ) -> Any :
168+ def __getitem__ (cls , key : str ) -> Any :
150169 return cls ._enum_member_map_ [key ]
151170
152171 def __setattr__ (cls , name : str , value : Any ) -> None :
@@ -164,21 +183,17 @@ def __instancecheck__(self, instance: Any) -> bool:
164183 return False
165184
166185
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 ]]
186+ if TYPE_CHECKING :
187+ from enum import Enum
188+ else :
175189
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
190+ class Enum (metaclass = EnumMeta ):
191+ @classmethod
192+ def try_value (cls , value : Any ) -> Any :
193+ try :
194+ return cls ._enum_value_map_ [value ]
195+ except (KeyError , TypeError ):
196+ return value
182197
183198
184199class KeyFormat (Enum ):
@@ -580,9 +595,9 @@ def _from_str(cls: type[Self], string: str) -> Self:
580595
581596
582597def create_unknown_value (cls : type [E ], val : Any ) -> NewValue :
583- value_cls = cls ._enum_value_cls_
598+ value_cls = cls ._enum_value_cls_ # type: ignore # This is narrowed below
584599 name = f'UNKNOWN_{ val } '
585- return value_cls (name = name , value = val )
600+ return value_cls (name = name , value = val ) # type: ignore
586601
587602
588603def try_enum (cls : type [E ], val : Any ) -> E :
@@ -591,6 +606,6 @@ def try_enum(cls: type[E], val: Any) -> E:
591606 If it fails it returns a proxy invalid value instead.
592607 """
593608 try :
594- return cls ._enum_value_map_ [val ]
609+ return cls ._enum_value_map_ [val ] # type: ignore # All errors are caught below
595610 except (KeyError , TypeError , AttributeError ):
596611 return create_unknown_value (cls , val )
0 commit comments