12
12
Dict ,
13
13
Optional ,
14
14
Tuple ,
15
+ Type ,
15
16
)
16
17
17
-
18
18
if TYPE_CHECKING :
19
19
from collections .abc import (
20
20
Generator ,
@@ -31,17 +31,22 @@ def _is_descriptor(obj: object) -> bool:
31
31
return (
32
32
hasattr (obj , "__get__" ) or hasattr (obj , "__set__" ) or hasattr (obj , "__delete__" )
33
33
)
34
+ if TYPE_CHECKING :
35
+ BaseMetaType = EnumMeta
36
+ BaseType = IntEnum
37
+ else :
38
+ BaseMetaType = type
39
+ BaseType = int
34
40
35
-
36
- class EnumType (EnumMeta if TYPE_CHECKING else type ):
41
+ class EnumType (BaseMetaType ):
37
42
_value_map_ : Mapping [int , Enum ]
38
- _member_map_ : Mapping [str , Enum ]
43
+ _member_map_ : Mapping [str , Enum ] # type: ignore[assignment]
39
44
40
45
def __new__ (
41
46
mcs , name : str , bases : Tuple [type , ...], namespace : Dict [str , Any ]
42
- ) -> Self :
43
- value_map = {}
44
- member_map = {}
47
+ ) -> Type[ Enum ] :
48
+ value_map : dict [ str , Enum ] = {}
49
+ member_map : dict [ str , Enum ] = {}
45
50
46
51
new_mcs = type (
47
52
f"{ name } Type" ,
@@ -60,7 +65,7 @@ def __new__(
60
65
if not _is_descriptor (value ) and not name .startswith ("__" )
61
66
}
62
67
63
- cls = type .__new__ (
68
+ cls : Type [ Enum ] = type .__new__ (
64
69
new_mcs ,
65
70
name ,
66
71
bases ,
@@ -72,7 +77,7 @@ def __new__(
72
77
for name , value in members .items ():
73
78
member = value_map .get (value )
74
79
if member is None :
75
- member = cls .__new__ (cls , name = name , value = value ) # type: ignore
80
+ member = cls .__new__ (cls , name = name , value = value )
76
81
value_map [value ] = member
77
82
member_map [name ] = member
78
83
type .__setattr__ (new_mcs , name , member )
@@ -81,56 +86,65 @@ def __new__(
81
86
82
87
if not TYPE_CHECKING :
83
88
89
+ @classmethod
84
90
def __call__ (cls , value : int ) -> Enum :
85
91
try :
86
92
return cls ._value_map_ [value ]
87
93
except (KeyError , TypeError ):
88
94
raise ValueError (f"{ value !r} is not a valid { cls .__name__ } " ) from None
89
95
96
+ @classmethod
90
97
def __iter__ (cls ) -> Generator [Enum , None , None ]:
91
98
yield from cls ._member_map_ .values ()
92
99
93
- if sys .version_info >= (3 , 8 ): # 3.8 added __reversed__ to dict_values
100
+ if sys .version_info >= (3 , 8 ):
94
101
102
+ @classmethod
95
103
def __reversed__ (cls ) -> Generator [Enum , None , None ]:
96
104
yield from reversed (cls ._member_map_ .values ())
97
105
98
106
else :
99
107
108
+ @classmethod
100
109
def __reversed__ (cls ) -> Generator [Enum , None , None ]:
101
110
yield from reversed (tuple (cls ._member_map_ .values ()))
102
111
112
+ @classmethod
103
113
def __getitem__ (cls , key : str ) -> Enum :
104
114
return cls ._member_map_ [key ]
105
115
106
- @property
116
+ @classmethod
107
117
def __members__ (cls ) -> MappingProxyType [str , Enum ]:
108
118
return MappingProxyType (cls ._member_map_ )
109
119
120
+ @classmethod
110
121
def __repr__ (cls ) -> str :
111
122
return f"<enum { cls .__name__ !r} >"
112
123
113
- def __len__ (cls ) -> int :
124
+ @classmethod
125
+ def __len__ (cls ) -> int :
114
126
return len (cls ._member_map_ )
115
127
116
- def __setattr__ (cls , name : str , value : Any ) -> Never :
117
- raise AttributeError (f"{ cls .__name__ } : cannot reassign Enum members." )
128
+ @classmethod
129
+ def __setattr__ (cls , name : str , value : Any ) -> Never :
130
+ raise AttributeError (f"{ cls .__name__ } : cannot reassign Enum classes." )
118
131
132
+ @classmethod
119
133
def __delattr__ (cls , name : str ) -> Never :
120
- raise AttributeError (f"{ cls .__name__ } : cannot delete Enum members ." )
134
+ raise AttributeError (f"{ cls .__name__ } : cannot delete Enum classes ." )
121
135
136
+ @classmethod
122
137
def __contains__ (cls , member : object ) -> bool :
123
- return isinstance (member , cls ) and member .name in cls ._member_map_
124
-
138
+ return isinstance (member , cls ) and isinstance (member , Enum ) and member .name in cls ._member_map_
125
139
126
- class Enum (IntEnum if TYPE_CHECKING else int , metaclass = EnumType ):
140
+ class Enum (BaseType , metaclass = EnumType ):
127
141
"""
128
142
The base class for protobuf enumerations, all generated enumerations will
129
143
inherit from this. Emulates `enum.IntEnum`.
130
144
"""
131
145
132
- name : Optional [ str ]
133
- value : int
146
+ name : str
147
+ value : int # type: ignore[misc]
134
148
135
149
if not TYPE_CHECKING :
136
150
@@ -178,7 +192,10 @@ def try_value(cls, value: int = 0) -> Self:
178
192
``value`` isn't actually a member.
179
193
"""
180
194
try :
181
- return cls ._value_map_ [value ]
195
+ value = cls ._value_map_ [value ]
196
+ if not isinstance (value , type (cls )):
197
+ raise TypeError (f'{ value } should be of same type as { cls .__name__ } ' )
198
+ return value
182
199
except (KeyError , TypeError ):
183
200
return cls .__new__ (cls , name = None , value = value )
184
201
@@ -197,6 +214,9 @@ def from_string(cls, name: str) -> Self:
197
214
The member was not found in the Enum.
198
215
"""
199
216
try :
200
- return cls ._member_map_ [name ]
217
+ member = cls ._member_map_ [name ]
218
+ if not isinstance (member , type (cls )):
219
+ raise TypeError (f'{ member } should be of the same type as { cls .__name__ } ' )
220
+ return member
201
221
except KeyError as e :
202
222
raise ValueError (f"Unknown value { name } for enum { cls .__name__ } " ) from e
0 commit comments