Skip to content

Commit 559ff60

Browse files
committed
Save version 1.1.0
Signed-off-by: Ihor Nehrutsa <Ihor.Nehrutsa@gmail.com>
1 parent 0aaf841 commit 559ff60

2 files changed

Lines changed: 444 additions & 0 deletions

File tree

python-stdlib/enum/enum_1.py

Lines changed: 272 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,272 @@
1+
# enum.py
2+
# version="1.1.0"
3+
4+
_Err = "no such attribute: "
5+
6+
7+
class ValueWrapper:
8+
"""Universal wrapper for accessing values via .value or calling ()"""
9+
__slots__ = ('_v', )
10+
11+
def __init__(self, v):
12+
self._v = v
13+
14+
@property
15+
def value(self):
16+
return self._v
17+
18+
def __call__(self):
19+
return self._v
20+
21+
def __repr__(self):
22+
return repr(self._v)
23+
24+
def __str__(self):
25+
return str(self._v)
26+
27+
# Type conversion
28+
def __int__(self):
29+
return int(self._v)
30+
31+
def __float__(self):
32+
return float(self._v)
33+
34+
def __index__(self):
35+
return int(self._v)
36+
37+
def __bool__(self):
38+
return bool(self._v)
39+
40+
# Helper function to extract the raw value
41+
def _get_v(self, other):
42+
return other._v if isinstance(other, ValueWrapper) else other
43+
44+
# Arithmetic and Bitwise operations (Forward)
45+
def __add__(self, other):
46+
return self._v + self._get_v(other)
47+
48+
def __sub__(self, other):
49+
return self._v - self._get_v(other)
50+
51+
def __mul__(self, other):
52+
return self._v * self._get_v(other)
53+
54+
def __truediv__(self, other):
55+
return self._v / self._get_v(other)
56+
57+
def __floordiv__(self, other):
58+
return self._v // self._get_v(other)
59+
60+
def __mod__(self, other):
61+
return self._v % self._get_v(other)
62+
63+
def __pow__(self, other):
64+
return self._v**self._get_v(other)
65+
66+
def __and__(self, other):
67+
return self._v & self._get_v(other)
68+
69+
def __or__(self, other):
70+
return self._v | self._get_v(other)
71+
72+
def __xor__(self, other):
73+
return self._v ^ self._get_v(other)
74+
75+
def __lshift__(self, other):
76+
return self._v << self._get_v(other)
77+
78+
def __rshift__(self, other):
79+
return self._v >> self._get_v(other)
80+
81+
# Arithmetic and Bitwise operations (Reflected)
82+
def __radd__(self, other):
83+
return self._get_v(other) + self._v
84+
85+
def __rsub__(self, other):
86+
return self._get_v(other) - self._v
87+
88+
def __rmul__(self, other):
89+
return self._get_v(other) * self._v
90+
91+
def __rtruediv__(self, other):
92+
return self._get_v(other) / self._v
93+
94+
def __rfloordiv__(self, other):
95+
return self._get_v(other) // self._v
96+
97+
def __rand__(self, other):
98+
return self._get_v(other) & self._v
99+
100+
def __ror__(self, other):
101+
return self._get_v(other) | self._v
102+
103+
def __rxor__(self, other):
104+
return self._get_v(other) ^ self._v
105+
106+
def __rlshift__(self, other):
107+
return self._get_v(other) << self._v
108+
109+
def __rrshift__(self, other):
110+
return self._get_v(other) >> self._v
111+
112+
# Unary operators
113+
def __neg__(self):
114+
return -self._v
115+
116+
def __pos__(self):
117+
return +self._v
118+
119+
def __abs__(self):
120+
return abs(self._v)
121+
122+
def __invert__(self):
123+
return ~self._v
124+
125+
# Comparison
126+
def __eq__(self, other):
127+
return self._v == self._get_v(other)
128+
129+
def __lt__(self, other):
130+
return self._v < self._get_v(other)
131+
132+
def __le__(self, other):
133+
return self._v <= self._get_v(other)
134+
135+
def __gt__(self, other):
136+
return self._v > self._get_v(other)
137+
138+
def __ge__(self, other):
139+
return self._v >= self._get_v(other)
140+
141+
def __ne__(self, other):
142+
return self._v != self._get_v(other)
143+
144+
145+
def enum(**kw_args): # `**kw_args` kept backwards compatible as in the Internet examples
146+
return Enum(kw_args)
147+
148+
149+
class Enum(dict):
150+
def __init__(self, arg=None, **kwargs):
151+
super().__init__()
152+
# Use __dict__ directly for internal flags
153+
# to avoid cluttering the dictionary keyspace
154+
super().__setattr__('_is_loading', True)
155+
156+
# 1. Collect class-level attributes (constants)
157+
self._scan_class_attrs()
158+
# 2. Add arguments from the constructor
159+
if arg: self.append(arg)
160+
if kwargs: self.append(kwargs)
161+
162+
super().__setattr__('_is_loading', False)
163+
164+
def _scan_class_attrs(self):
165+
cls = self.__class__
166+
# Define attributes to skip (internal or explicitly requested)
167+
skipped = getattr(cls, '__skipped__', ())
168+
169+
for key in dir(cls):
170+
# Skip internal names, methods, and excluded attributes
171+
if key.startswith('_') or key in ('append', 'is_value', 'key_from_value'):
172+
continue
173+
if key in skipped:
174+
continue
175+
176+
val = getattr(cls, key)
177+
# Only wrap non-callable attributes (constants)
178+
if not callable(val):
179+
self[key] = ValueWrapper(val)
180+
181+
def append(self, arg=None, **kwargs):
182+
if isinstance(arg, dict):
183+
for k, v in arg.items():
184+
self[k] = ValueWrapper(v)
185+
else:
186+
self._arg = arg # for __str__()
187+
if kwargs:
188+
for k, v in kwargs.items():
189+
self[k] = ValueWrapper(v)
190+
return self
191+
192+
def __getattr__(self, key):
193+
if key in self:
194+
return self[key]
195+
raise AttributeError(_Err + key)
196+
197+
def __setattr__(self, key, value):
198+
if self._is_loading or key.startswith('_'):
199+
# Record directly into memory as a regular variable
200+
super().__setattr__(key, value)
201+
else:
202+
# Handle as an Enum element (wrap in ValueWrapper)
203+
self[key] = ValueWrapper(value)
204+
205+
def is_value(self, value):
206+
return any(v._v == value for v in self.values())
207+
208+
def key_from_value(self, value):
209+
for k, v in self.items():
210+
if v._v == value: return f"{self.__class__.__name__}.{k}"
211+
raise ValueError(_Err + str(value))
212+
213+
def __dir__(self):
214+
# 1. Dictionary keys (your data: X1, X2, etc.)
215+
data_keys = list(self.keys())
216+
# 2. Class attributes (your methods: append, is_value, etc.)
217+
class_stuff = list(dir(self.__class__))
218+
# 3. Parent class attributes (for completeness)
219+
parent_attrs = list(dir(super()))
220+
# Combine and remove duplicates using set for clarity
221+
#return list(set(data_keys + class_stuff + parent_attrs))
222+
return list(set(data_keys + class_stuff))
223+
224+
def __call__(self, value):
225+
if self.is_value(value):
226+
return value
227+
raise ValueError(_Err + f"{value}")
228+
229+
230+
if __name__ == "__main__":
231+
# --- Usage Examples ---
232+
233+
# 1. GPIO and Hardware Configuration
234+
class Pins(Enum):
235+
LED = 2
236+
BUTTON = 4
237+
__skipped__ = ('RESERVED_PIN', )
238+
RESERVED_PIN = 0
239+
240+
pins = Pins(SDA=21, SCL=22)
241+
print(f"I2C SDA Pin: {pins.SDA}")
242+
print(f"Is 21 a valid pin? {pins.is_value(21)}")
243+
244+
# 2. Math and Logic
245+
brightness = Enum(MIN=0, STEP=25, MAX=255)
246+
print(f"Next level: {brightness.MIN + brightness.STEP // 2}")
247+
print(f"Calculation: {brightness.MIN + 2 * brightness.STEP}")
248+
249+
# Direct arithmetic without .value
250+
print(f"Complex math: {100 + brightness.STEP}")
251+
252+
# 3. State Machine (Dynamic Expansion)
253+
status = Enum(IDLE=0, CONNECTING=1)
254+
status.append(CONNECTED=2, ERROR=3)
255+
status.DISCONNECTING = 4
256+
257+
for name, val in status.items():
258+
print(f"Status {name} has code {val}")
259+
260+
# 4. Working with different types
261+
commands = Enum(START="CMD_START", STOP="CMD_STOP", REBOOT_CODE=0xDEADBEEF, IS_ACTIVE=True)
262+
263+
if commands.IS_ACTIVE:
264+
print(f"Running command: {commands.START}")
265+
266+
# 5. Class Config and dir()
267+
class WebConfig(Enum):
268+
PORT = 80
269+
TIMEOUT = 5.0
270+
271+
config = WebConfig({'IP': '192.168.1.1'})
272+
print(f"Available keys in config: {list(config.keys())}")

0 commit comments

Comments
 (0)