Skip to content

Commit 39b369c

Browse files
committed
python-stdlib\enum\enum.py: Add Enum class.
Signed-off-by: Ihor Nehrutsa <Ihor.Nehrutsa@gmail.com>
1 parent 0400c56 commit 39b369c

5 files changed

Lines changed: 615 additions & 0 deletions

File tree

python-stdlib/enum/README.md

Lines changed: 201 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,201 @@
1+
# Enum Library
2+
3+
This library provides a lightweight, memory-efficient `Enum` implementation designed for MicroPython environments. It focuses on immutability, reverse lookup capabilities, and serialization support without the complexity of metaclasses.
4+
5+
---
6+
7+
## Core Features
8+
* **Immutability**: Enum members (`EnumValue`) are protected against modification. Any attempt to change their name or value raises an `AttributeError`.
9+
* **Static Design**: Once an Enum instance is initialized, it is "frozen." You cannot add new attributes or delete existing members.
10+
* **Dual Reverse Lookup**:
11+
* **Class Constructor**: Retrieve a member by value using the class name (e.g., `Status(1)`).
12+
* **Instance Call**: Retrieve a member by value by calling the instance (e.g., `s(1)`).
13+
* **Serialization Support**: Implements `__repr__` such that `obj == eval(repr(obj))`, allowing easy restoration of Enum states.
14+
* **Functional API**: Supports dynamic creation of Enums at runtime.
15+
16+
---
17+
18+
## Usage Examples
19+
20+
### 1. Standard Class Definition
21+
Define your enumeration by inheriting from the `Enum` class. Class-level constants are automatically converted into `EnumValue` objects upon initialization.
22+
23+
```python
24+
from enum import Enum
25+
26+
class Color(Enum):
27+
RED = 'red'
28+
GREEN = 'green'
29+
30+
# Initialize the enum to process attributes
31+
c = Color()
32+
33+
print(c.RED) # Output: RED: red
34+
print(c.RED.name) # Output: RED
35+
print(c.RED.value) # Output: red
36+
print(c.RED()) # Output: red
37+
print(c.is_value("RED")) # Output: true
38+
print(c.is_value(Color.RED)) # Output: true
39+
print(c.is_value('red')) # Output: true
40+
print(c.list()) # Output: [Color.RED: red, Color.GREEN: green]
41+
print([m for m in c]) # Output: [Color.RED: red, Color.GREEN: green]
42+
print([m.name for m in c]) # Output: ['RED', 'GREEN']
43+
print([m.value for m in c]) # Output: ['red', 'green']
44+
```
45+
46+
47+
### 2. Reverse Lookup
48+
The library provides two ways to find a member based on its raw value.
49+
50+
```python
51+
class Status(Enum):
52+
IDLE = 0
53+
RUNNING = 1
54+
55+
# Method A: Via Class (Simulates interpreting hardware/network bytes)
56+
# Uses __new__ logic to return the correct EnumValue
57+
current_status = Status(1)
58+
print(current_status.name) # Output: RUNNING
59+
print(current_status.value) # Output: 1
60+
print(current_status) # Output: Status.RUNNING: 1
61+
print(current_status()) # Output: 1
62+
63+
# Method B: Via Instance Call
64+
s = Status()
65+
print(s(0).name) # Output: IDLE
66+
print(s(0).value) # Output: 0
67+
print(s(0)) # Output: Status.IDLE: 0
68+
print(s(0)()) # Output: 0
69+
```
70+
71+
72+
### 3. Functional API (Dynamic Creation)
73+
If you need to create an Enum from external data (like a JSON config), use the functional constructor.
74+
75+
```python
76+
# Create a dynamic Enum instance
77+
State = Enum(name='State', names={'ON': 1, 'OFF': 2})
78+
79+
print(State) # Output: Enum(name='State', names={'ON': 1, 'OFF': 2})
80+
print(State.ON) # Output: State.ON: 1
81+
print(State.ON.name) # Output: ON
82+
print(State.ON.value) # Output: 1
83+
print(State.ON()) # Output: 1
84+
assert State.ON == 1 # Comparison
85+
assert State.ON() == 1 #
86+
assert State.ON.value == 1 #
87+
assert State.ON.name == "ON" #
88+
```
89+
90+
91+
### 4. Serialization (Repr / Eval)
92+
The library ensures that the string representation can be used to perfectly reconstruct the object.
93+
94+
```python
95+
from enum import Enum
96+
97+
class Color(Enum):
98+
RED = 'red'
99+
GREEN = 'green'
100+
BLUE = 3
101+
102+
colors = Color()
103+
# Get serialized string
104+
serialized = repr(colors)
105+
# Reconstruct object
106+
restored_colors = eval(serialized)
107+
108+
print(f"Original: {colors}") # Output: Original: Enum(name='Color', names={'BLUE': 3, 'RED': 'red', 'GREEN': 'green'})
109+
print(f"Restored: {restored_colors}") # Output: Restored: Enum(name='Color', names={'BLUE': 3, 'RED': 'red', 'GREEN': 'green'})
110+
print(colors == restored_colors) # Output: True
111+
```
112+
113+
114+
---
115+
116+
## API Reference
117+
118+
### `EnumValue`
119+
The object representing a specific member of an Enum.
120+
* `.name`: The string name of the member.
121+
* `.value`: The raw value associated with the member.
122+
* `()`: Calling the member object returns its raw value (e.g., `c.RED() -> 'red'`).
123+
124+
### `Enum`
125+
The base class for all enumerations.
126+
* `list()`: Returns a list of all defined members.
127+
* `is_value(value)`: Returns `True` if the provided raw value exists within the Enum.
128+
* `__len__`: Returns the total number of members.
129+
* `__iter__`: Allows looping through members (e.g., `[m.name for m in color_inst]`).
130+
131+
---
132+
133+
## Error Handling
134+
* **`AttributeError`**:
135+
* Raised when attempting to modify an `EnumValue`.
136+
* Raised when attempting to add new members to an initialized Enum.
137+
* Raised when a class-level lookup (`Status(999)`) fails.
138+
* Raised when an instance-level lookup (`s(999)`) fails.
139+
140+
## Compare with CPython
141+
142+
```python
143+
# Run on MicroPython v1.28.0 on 2026-04-06; Generic ESP32 module with ESP32
144+
# Run on Python 3.12.10
145+
from enum import Enum
146+
147+
# class syntax
148+
class Color(Enum):
149+
RED = 1
150+
GREEN = 2
151+
BLUE = 3
152+
153+
# OR
154+
# functional syntax
155+
# Color = Enum('Color', {'RED': 1, 'GREEN': 2, 'BLUE': 3})
156+
157+
# List enum members
158+
try:
159+
print(list(Color))
160+
# [<Color.RED: 1>, <Color.GREEN: 2>, <Color.BLUE: 3>]
161+
except:
162+
print(Color.list())
163+
# [RED: 1, GREEN: 2, BLUE: 3]
164+
165+
# Accessing enum member by name
166+
print(Color.GREEN, type(Color.GREEN))
167+
# Color.GREEN <enum 'Color'>
168+
# GREEN: 2 <class 'EnumValue'>
169+
170+
# Accessing enum member by name
171+
try:
172+
print(Color['GREEN'])
173+
# Color.GREEN
174+
except:
175+
print(Color('GREEN'))
176+
# GREEN: 2
177+
178+
# Accessing enum member by value
179+
print(Color(2))
180+
# Color.GREEN
181+
182+
# Accessing enum member name
183+
print(Color.GREEN.name, type(Color.GREEN.name))
184+
# GREEN <class 'str'>
185+
186+
# Accessing enum member value
187+
print(Color.GREEN.value, type(Color.GREEN.value))
188+
# 2 <class 'int'>
189+
```
190+
191+
### Output is:
192+
193+
| MicroPython v1.28.0 | Python 3.12.10 |
194+
| :--- | :--- |
195+
| [Color.RED: 1, Color.GREEN: 2, Color.BLUE: 3] | [<Color.RED: 1>, <Color.GREEN: 2>, <Color.BLUE: 3>] |
196+
| Color.GREEN: 2 <class 'EnumValue'> | Color.GREEN <enum 'Color'> |
197+
| Color.GREEN: 2 | Color.GREEN |
198+
| Color.GREEN: 2 | Color.GREEN |
199+
| GREEN <class 'str'> | GREEN <class 'str'> |
200+
| 2 <class 'int'> | 2 <class 'int'> |
201+

0 commit comments

Comments
 (0)