From fb5bcae46b3f30a4d49a190c2aeca5813d66675f Mon Sep 17 00:00:00 2001 From: Ihor Nehrutsa Date: Wed, 5 Mar 2025 12:24:05 +0200 Subject: [PATCH 1/3] python-stdlib\enum\enum.py: Add Enum class. Signed-off-by: Ihor Nehrutsa --- python-stdlib/enum/enum.py | 211 ++++++++++++++++++++++++++++++++ python-stdlib/enum/enum_test.py | 86 +++++++++++++ python-stdlib/enum/manifest.py | 3 + 3 files changed, 300 insertions(+) create mode 100644 python-stdlib/enum/enum.py create mode 100644 python-stdlib/enum/enum_test.py create mode 100644 python-stdlib/enum/manifest.py diff --git a/python-stdlib/enum/enum.py b/python-stdlib/enum/enum.py new file mode 100644 index 000000000..9d62faaf4 --- /dev/null +++ b/python-stdlib/enum/enum.py @@ -0,0 +1,211 @@ +# enum.py + +_Err = "no such attribute: " + + +class int_value(int): + @property + def value(self) -> int: + return self + + def __call__(self) -> int: + return self + + +class str_value(str): + @property + def value(self) -> str: + return self + + def __call__(self) -> str: + return self + + +class bool_value(bool): + @property + def value(self) -> bool: + return self + + def __call__(self) -> bool: + return self + + +class float_value(float): + @property + def value(self) -> float: + return self + + def __call__(self) -> float: + return self + + +def get_class_value(value): + if type(value) is int: + return int_value(value) + elif type(value) is bool: + return bool_value(value) + elif type(value) is float: + return float_value(value) + elif type(value) is str: + return str_value(value) + else: + return value + + +def enum(**kw_args): # `**kw_args` kept backwards compatible as in the Internet examples + return Enum(kw_args) + + +class Enum(dict): + def __init__(self, arg=None): # `arg` is dict() compatible + super().__init__() + self._arg = None + if not arg is None: + self.append(arg) + self._is_enums_from_class = False + self._get_enums_from_class() + + def _update(self, key, value): + self.update({key: get_class_value(value)}) + + def append(self, arg=None, **kw_args): + if len(kw_args): + for key, value in kw_args.items(): + self._update(key, value) + if type(arg) == type(dict()): + for key, value in arg.items(): + self._update(key, value) + else: + self._arg = arg # for __str__() + return self + + def __repr__(self): + d = self.copy() + try: + d.pop("_arg") + except: + pass + return str(d) + + def __str__(self): + value = None + try: + value = self._arg + except: + pass + if not value is None: + if self.is_value(value): + self._arg = None + return value + raise ValueError(_Err + f"{value}") + return self.__qualname__ + "(" + self.__repr__() + ")" + + def is_value(self, value): + if value in self.values(): + return True + return False + + def key_from_value(self, value): + for key in self: + if self.get(key) == value: + return self.__qualname__ + "." + key + raise ValueError(_Err + f"{value}") + + def __call__(self, value): + if self.is_value(value): + return value + raise ValueError(_Err + f"{value}") + + def __getattr__(self, key): + try: + if key in self: + return self[key] + else: + raise KeyError(_Err + f"{key}") + except: + raise KeyError(_Err + f"{key}") + + def __setattr__(self, key, value): + if key == "_arg": + self[key] = value + return + try: + self[key] = get_class_value(value) + except: + raise KeyError(_Err + f"{key}") + + def __delattr__(self, key): + try: + if key in self: + del self[key] + else: + raise KeyError(_Err + f"{key}") + except: + raise KeyError(_Err + f"{key}") + + def __len__(self): + return len(tuple(self.keys())) + + def __dir__(self): + return dir(Enum) + + def _get_enums_from_class(self): + ## Class XX(Enum): + ## X1 = 1 + ## X2 = 2 + + if not self._is_enums_from_class: + keys = dir(eval(self.__qualname__)) + + def try_remove(item): + try: + keys.remove(item) + except: + pass + + for item in dir(dict): + try_remove(item) + + _list = [ + "__init__", + "__class__init__", + "__call__", + "__Errases__", + "__module__", + "__qualname__", + "__len__", + "__lt__", + "__le__", + "__eq__", + "__ne__", + "__gt__", + "__ge__", + "__dir__", + "__delattr__", + "__getattr__", + "__setattr__", + "__str__", + "__repr__", + "_get_enums_from_class", + "_arg", + "_update", + "is_value", + "key_from_value", + "append", + ] + for item in _list: + try_remove(item) + module = "" + if self.__module__ != "__main__": + module = self.__module__ + "." + for key in keys: + try: + value = eval(f"{module}{self.__qualname__}.{key}") + except: + value = eval(f"{self.__qualname__}.{key}") + self._update(key, value) + keys.clear() + del keys + self._is_enums_from_class = True # 1 !!! + self.pop("_is_enums_from_class") # 2 !!! + return self diff --git a/python-stdlib/enum/enum_test.py b/python-stdlib/enum/enum_test.py new file mode 100644 index 000000000..dbe411d77 --- /dev/null +++ b/python-stdlib/enum/enum_test.py @@ -0,0 +1,86 @@ +# enum_test.py + +from enum import Enum, enum + + +class Direction(Enum): + CW = "CW" + CCW = "CCW" + + +class State(Direction): + Stop = 1 + Run = 2 + Ready = 3 + Disabled = False + Enabled = True + + +state = Enum() +print(state) +state = Direction() +print(state) +state = State() +print(state) +state = State({"X": 1.0, "Y": 2.0}) +print(state) +state.Idle = 10 +state.Triggered = 20 +state.Lockout = 30 +print(state) + +print("Direction(Direction.CCW):", Direction(Direction.CCW)) +print("Direction('CW'):", Direction("CW")) +print("state(10):", state(10)) + +print("state('CW'):", state("CW")) +print("type(state('CW')):", type(state("CW"))) + +print("state.key_from_value(20):", state.key_from_value(20)) +print("len(state):", len(state)) + +print("state.Idle:", state.Idle) +print("type(state.Idle):", type(state.Idle)) + +current_state = state.Idle +print("current_state:", current_state) +if current_state == state.Idle: + print(" Idle state") +if current_state != state.Triggered: + print(" Not a triggered state") + current_state = state.Idle +print("current_state:", current_state) +print("state.key_from_value(current_state):", state.key_from_value(current_state)) + +state2 = eval(str(state)) +print(state2) +print("state == state2:", state == state2) + +del state.Triggered +print(state) +print("state == state2:", state == state2) + +print("state.keys():", state.keys()) +print("state.values():", state.values()) +print("state.items():", state.items()) + +try: + del state.stop +except Exception as e: + print("Exception:", e) + +assert current_state == state.Idle +assert current_state != state.Disabled +assert state.Idle != state.Disabled +print( + "State(State.Ready):", + State(State.Ready), + "type(State.Ready):", + type(State(State.Ready)), + "type(State.Ready):", + type(State.Ready), +) +assert int(str(State(State.Ready))) == State.Ready +assert int(str(State(State.Ready))) != State.Disabled +print("will raise exception") +del state.Triggered diff --git a/python-stdlib/enum/manifest.py b/python-stdlib/enum/manifest.py new file mode 100644 index 000000000..1a6450dca --- /dev/null +++ b/python-stdlib/enum/manifest.py @@ -0,0 +1,3 @@ +metadata(version="0.0.1") + +module("enum.py") From 8edf766ffcfa25135806e4aff8e40647cbaf9aa9 Mon Sep 17 00:00:00 2001 From: Ihor Nehrutsa Date: Tue, 11 Mar 2025 10:08:10 +0200 Subject: [PATCH 2/3] tools\ci.sh: Add enum_test.py to the CI. Signed-off-by: Ihor Nehrutsa --- tools/ci.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/ci.sh b/tools/ci.sh index a5fcdf22e..d9b8f4d94 100755 --- a/tools/ci.sh +++ b/tools/ci.sh @@ -54,6 +54,7 @@ function ci_package_tests_run { python-stdlib/base64/test_base64.py \ python-stdlib/binascii/test_binascii.py \ python-stdlib/collections-defaultdict/test_defaultdict.py \ + python-stdlib/enum/enum_test.py \ python-stdlib/functools/test_partial.py \ python-stdlib/functools/test_reduce.py \ python-stdlib/heapq/test_heapq.py \ From 6ab2ebe906a9093f07ff7d5244395b2a74fd0bfe Mon Sep 17 00:00:00 2001 From: Ihor Nehrutsa Date: Wed, 12 Mar 2025 09:28:30 +0200 Subject: [PATCH 3/3] tools\ci.sh: Add test_enum.py to the CI. Signed-off-by: Ihor Nehrutsa --- python-stdlib/enum/manifest.py | 2 +- python-stdlib/enum/{enum_test.py => test_enum.py} | 7 ++++++- tools/ci.sh | 2 +- 3 files changed, 8 insertions(+), 3 deletions(-) rename python-stdlib/enum/{enum_test.py => test_enum.py} (91%) diff --git a/python-stdlib/enum/manifest.py b/python-stdlib/enum/manifest.py index 1a6450dca..6b6b821ca 100644 --- a/python-stdlib/enum/manifest.py +++ b/python-stdlib/enum/manifest.py @@ -1,3 +1,3 @@ -metadata(version="0.0.1") +metadata(version="1.0.0") module("enum.py") diff --git a/python-stdlib/enum/enum_test.py b/python-stdlib/enum/test_enum.py similarity index 91% rename from python-stdlib/enum/enum_test.py rename to python-stdlib/enum/test_enum.py index dbe411d77..1ad848f0a 100644 --- a/python-stdlib/enum/enum_test.py +++ b/python-stdlib/enum/test_enum.py @@ -83,4 +83,9 @@ class State(Direction): assert int(str(State(State.Ready))) == State.Ready assert int(str(State(State.Ready))) != State.Disabled print("will raise exception") -del state.Triggered +try: + del state.Triggered +except Exception as e: + print("Exception:", e) + +print("OK") diff --git a/tools/ci.sh b/tools/ci.sh index d9b8f4d94..a109d1c45 100755 --- a/tools/ci.sh +++ b/tools/ci.sh @@ -54,7 +54,7 @@ function ci_package_tests_run { python-stdlib/base64/test_base64.py \ python-stdlib/binascii/test_binascii.py \ python-stdlib/collections-defaultdict/test_defaultdict.py \ - python-stdlib/enum/enum_test.py \ + python-stdlib/enum/test_enum.py \ python-stdlib/functools/test_partial.py \ python-stdlib/functools/test_reduce.py \ python-stdlib/heapq/test_heapq.py \ pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy