11# enum.py
2- # version="1.2.2 "
2+ # version="1.2.3 "
33
44
55class EnumValue :
@@ -9,10 +9,10 @@ def __init__(self, value, name):
99 object .__setattr__ (self , 'name' , name )
1010
1111 def __repr__ (self ):
12- return f"< { self .name } : { self .value } > "
12+ return f"{ self .name } : { self .value } "
1313
14- def __str__ (self ):
15- return str (self .value )
14+ # def __str__(self):
15+ # return str(self.value)
1616
1717 def __call__ (self ):
1818 return self .value
@@ -22,34 +22,35 @@ def __eq__(self, other):
2222 return self .value == other .value
2323 return self .value == other
2424
25- def __int__ (self ):
26- return self .value
25+ # def __int__(self):
26+ # return self.value
2727
2828 def __setattr__ (self , key , value ):
2929 raise AttributeError ("EnumValue is immutable" )
3030
3131
3232class Enum :
33- def __new__ (cls , * args , ** kwargs ):
33+ def __new__ (cls , name = None , names = None ):
3434 # Scenario 1: Reverse lookup by value (e.g., Status(1))
35- if len ( args ) == 1 :
35+ if name is not None and names is None :
3636 if cls is not Enum :
37- return cls ._lookup (args [0 ])
38- return super (Enum , cls ).__new__ (cls )
39-
40- # Scenario 2: Restriction on multiple positional arguments
41- elif len (args ) > 1 :
42- raise TypeError (f"{ cls .__name__ } () takes at most 1 positional argument ({ len (args )} given)" )
37+ return cls ._lookup (name )
4338
44- # Scenario 3: Creating an instance (e.g. Color() або Color(BLUE=3 ))
39+ # Scenario 2: Functional API (e.g., Enum('Color', {'RED': 1} ))
4540 return super (Enum , cls ).__new__ (cls )
4641
47- def __init__ (self , ** kwargs ):
42+ def __init__ (self , name = None , names = None ):
4843 # 1. Convert class-level attributes (constants) to EnumValue objects
4944 self ._scan_class_attrs ()
50- # 2. Add dynamic arguments from constructor
51- if kwargs :
52- self .append (** kwargs )
45+
46+ # Support Functional API: Enum('Name', {'KEY': VALUE})
47+ if name is not None and isinstance (names , dict ):
48+ for key , value in names .items ():
49+ # Prevent addition if the key already exists
50+ if not hasattr (self , key ):
51+ self ._update (key , value )
52+
53+ object .__setattr__ (self , '_initialized' , True )
5354
5455 @classmethod
5556 def _lookup (cls , value ):
@@ -63,7 +64,6 @@ def _lookup(cls, value):
6364 if not callable (attr ) and attr == value :
6465 # Wrap static numbers found in class definition
6566 return EnumValue (attr , key )
66- return attr
6767
6868 raise AttributeError (f"{ value } is not in { cls .__name__ } enum" )
6969
@@ -77,7 +77,7 @@ def _update(self, key, value):
7777 def _scan_class_attrs (self ):
7878 # Converts static class attributes into EnumValue objects
7979 # List of methods and internal names that should not be converted
80- ignored = ('append' , ' is_value' , 'list_members' )
80+ ignored = ('is_value' , 'list_members' )
8181 for key in dir (self .__class__ ):
8282 # Skip internal names and methods
8383 if key .startswith ('_' ) or key in ignored :
@@ -91,17 +91,13 @@ def _scan_class_attrs(self):
9191 def is_value (self , value ):
9292 return any (member .value == value for member in self )
9393
94- def append (self , ** kwargs ):
95- # Adds new members dynamically.
96- for key , value in kwargs .items ():
97- if hasattr (self , key ):
98- raise AttributeError (f"Enum key '{ key } ' is immutable" )
99- self ._update (key , value )
100-
10194 def __repr__ (self ):
102- members = [f"{ m .name } ={ m .value } " for m in self ]
103- # Return a string like: Color(RED=1, GREEN=2, BLUE=3)
104- return f"{ self .__class__ .__name__ } ({ ', ' .join (members )} )"
95+ # Supports the condition: obj == eval(repr(obj))
96+ members = {m .name : m .value for m in self }
97+ if self .__class__ .__name__ == 'Enum' :
98+ return f"Enum(name='Enum', names={ members } )"
99+ # Return a string like: Name(names={'KEY1': VALUE1, 'KEY2': VALUE2, ..})
100+ return f"{ self .__class__ .__name__ } (names={ members } )"
105101
106102 def __call__ (self , value ):
107103 for member in self :
@@ -110,8 +106,8 @@ def __call__(self, value):
110106 raise ValueError (f"no such value: { value } " )
111107
112108 def __setattr__ (self , key , value ):
113- if hasattr (self , key ) and isinstance ( getattr ( self , key ), EnumValue ):
114- raise AttributeError (f"Enum member ' { key } ' is immutable " )
109+ if hasattr (self , '_initialized' ):
110+ raise AttributeError (f"Enum ' { self . __class__ . __name__ } ' is static " )
115111 super ().__setattr__ (key , value )
116112
117113 def __delattr__ (self , key ):
@@ -128,58 +124,49 @@ def __iter__(self):
128124 if isinstance (attr , EnumValue ):
129125 yield attr
130126
131-
132- def enum (** kwargs ): # `**kwargs` kept backwards compatible as in the Internet examples
133- return Enum (** kwargs )
127+ def __eq__ (self , other ):
128+ if not isinstance (other , Enum ):
129+ return False
130+ return self .list_members () == other .list_members ()
134131
135132
136133if __name__ == '__main__' :
137134 # --- Usage Example 1 ---
138- # 1. Creation via class
135+ # Standard Class Definition
139136 class Color (Enum ):
140- RED = 1
141- GREEN = 2
137+ RED = 'red'
138+ GREEN = 'green'
142139
143- # 2. Create instance
140+ # Create instance
144141 c = Color ()
145142 print (f"Enum repr c: { c } " )
146143
147- # 3. Dynamic addition
148- c .append (BLUE = 3 )
149- print (f"c after append: { c } " )
150-
151- print ('dir(c):' , dir (c ))
152-
153- # 4. Immutability and name protection check
154- try :
155- c .append (append = True )
156- except AttributeError as e :
157- print (f"\n AttributeError: Reserved name protection: { e } \n " )
158-
159- # 5. Basic access
144+ # Basic access
160145 print (f"RED: Name={ c .RED .name } , Value={ c .RED .value } , EnumValue={ c .RED } , Call={ c .RED ()} " )
161146
162- # 6. Assertions
163- assert c .RED == 1
164- assert c .RED .value == 1
147+ # Assertions
165148 assert c .RED .name == 'RED'
149+ assert c .RED .value == 'red'
150+ assert c .RED == 'red'
151+ assert c .RED () == 'red'
166152
167- # 7. Reverse lookup
168- print (f"c(1) lookup object: { c (1 )} , Name={ c (1 ).name } " ) # RED
169- assert c (1 ).name == 'RED'
170- assert c (1 ) == 1
153+ # Reverse Lookup via instance call
154+ print (f"c('red') lookup object: { c ('red' )} , Name={ c ('red' ).name } , value={ c ('red' ).value } " ) # RED
155+ assert c ('red' ).name == 'RED'
156+ assert c ('red' ).value == 'red'
157+ assert c ('red' ) == 'red'
171158
172- # 8. Iteration
159+ # Iteration
173160 print ("Values list:" , [member .value for member in c ])
174161 print ("Names list:" , [member .name for member in c ])
175162
176163 try :
177- c (7 )
164+ c (999 )
178165 except ValueError as e :
179166 print (f"\n ValueError: { c } { e } \n " )
180167
181168 # --- Usage Example 2 ---
182- # 1. Define an Enum class
169+ # Define an Enum class
183170 class Status (Enum ):
184171 IDLE = 0
185172 RUNNING = 1
@@ -189,38 +176,48 @@ class Status(Enum):
189176 # This simulates receiving a byte from the hardware
190177 received_byte = 1
191178 status = Status (received_byte )
192- print (f"Lookup check: Received { received_byte } -> { status !r } " )
179+ print (f"Lookup check: Received { received_byte } -> { status } " )
193180 assert status == Status .RUNNING
194181 assert status .name == "RUNNING"
195182
196- # 3. Test: Comparisons
183+ # Test: Comparisons
197184 print (f"Comparison check: { status } == 1 is { status == 1 } " )
198185 assert status == 1
199186 assert status != 0
200187 assert status == Status .RUNNING
201188
202- # 4. Test: Immutability
189+ # Immutability Check
203190 try :
204- Status .RUNNING .value = 99
191+ Status .RUNNING .value = 999
205192 except AttributeError as e :
206193 print (f"\n Immutability check: Passed (Cannot modify EnumValue): { e } \n " )
207194
208- # 5. Test: Dynamic Append
209- powers = Enum ()
210- powers .append (LOW = 10 , HIGH = 100 )
211- print (f"Dynamic Enum check: { powers } " )
212- assert powers .LOW == 10
213-
214- # 6. Test: Iteration
195+ # Test: Iteration
215196 print ("Iteration check: " , end = "" )
216197 for m in Status ():
217198 print (f"{ m .name } , " , end = "" )
218199 print ("-> Passed" )
219200
220- # 7. Test: Error handling for invalid lookup
201+ # Test: Error handling for invalid lookup
221202 try :
222- Status (99 )
203+ Status (999 )
223204 except AttributeError as e :
224205 print (f"\n AttributeError: Invalid lookup check: Caught expected error -> { e } \n " )
225206
207+ # --- Example 3: Functional API and serialization ---
208+ print ("\n --- Functional API and Eval Check ---" )
209+
210+ # Verify that eval(repr(obj)) restores the object
211+ c2 = eval (repr (c ))
212+ print (f"Original: { repr (c )} " )
213+ print (f"Restored: { repr (c2 )} " )
214+ print (f"Objects are equal: { c == c2 } " )
215+ assert c == c2
216+
217+ # Direct creation using the Enum base class
218+ state = eval ("Enum(name='State', names={'ON':1, 'OFF':2})" )
219+ print (f"Functional Enum instance (state): { state } " )
220+ assert state .ON == 1
221+ assert state .ON .name == 'ON'
222+
226223 print ("\n All tests passed successfully!" )
0 commit comments