From 93f8c04ce620a43ea5bcd5abb635f8efa029086e Mon Sep 17 00:00:00 2001 From: Alter Ego <0x7c48@gmail.com> Date: Thu, 22 Feb 2024 20:27:23 +0100 Subject: [PATCH] Python BaseUniqueSortedEnum --- README.md | 79 +++++++++++++++++++++++++++++++++++++++++++++++++ python/enums.py | 71 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 150 insertions(+) create mode 100644 python/enums.py diff --git a/README.md b/README.md index 4ce3b00..a981c1b 100644 --- a/README.md +++ b/README.md @@ -2145,6 +2145,85 @@ and [Helping Modular Humanize AI Through Brand](https://www.metalab.com/blog/hel * [Apache TVM](https://tvm.apache.org) +## Python hints + +Python problem with PostgreSQL Enum type. +We need names and values as strings, and we need to maintain their order. + +```Python +import enum +from functools import total_ordering + + +@total_ordering +@enum.unique +class BaseUniqueSortedEnum(enum.Enum): + """Base unique enum class with ordering.""" + + def __new__(cls, *args, **kwargs): + obj = object.__new__(cls) + obj.index = len(cls.__members__) + 1 + return obj + + def __hash__(self) -> int: + return hash( + f"{self.__module__}_{self.__class__.__name__}_{self.name}_{self.value}" + ) + + def __eq__(self, other) -> bool: + self._check_type(other) + return super().__eq__(other) + + def __lt__(self, other) -> bool: + self._check_type(other) + return self.index < other.index + + def _check_type(self, other) -> None: + if type(self) != type(other): + raise TypeError(f"Different types of Enum: {self} != {other}") + + +class Dog(BaseUniqueSortedEnum): + BLOODHOUND = "BLOODHOUND" + WEIMARANER = "WEIMARANER" + SAME = "SAME" + + +class Cat(BaseUniqueSortedEnum): + BRITISH = "BRITISH" + SCOTTISH = "SCOTTISH" + SAME = "SAME" + + +assert Dog.BLOODHOUND < Dog.WEIMARANER +assert Dog.BLOODHOUND <= Dog.WEIMARANER +assert Dog.BLOODHOUND != Dog.WEIMARANER +assert Dog.BLOODHOUND == Dog.BLOODHOUND +assert Dog.WEIMARANER == Dog.WEIMARANER +assert Dog.WEIMARANER > Dog.BLOODHOUND +assert Dog.WEIMARANER >= Dog.BLOODHOUND + +assert Cat.BRITISH < Cat.SCOTTISH +assert Cat.BRITISH <= Cat.SCOTTISH +assert Cat.BRITISH != Cat.SCOTTISH +assert Cat.BRITISH == Cat.BRITISH +assert Cat.SCOTTISH == Cat.SCOTTISH +assert Cat.SCOTTISH > Cat.BRITISH +assert Cat.SCOTTISH >= Cat.BRITISH + +assert hash(Dog.BLOODHOUND) == hash(Dog.BLOODHOUND) +assert hash(Dog.WEIMARANER) == hash(Dog.WEIMARANER) +assert hash(Dog.BLOODHOUND) != hash(Dog.WEIMARANER) +assert hash(Dog.SAME) != hash(Cat.SAME) + +# raise TypeError +Dog.SAME <= Cat.SAME +Dog.SAME < Cat.SAME +Dog.SAME > Cat.SAME +Dog.SAME >= Cat.SAME +Dog.SAME != Cat.SAME +``` + # Contributing * Your contributions are always welcome! diff --git a/python/enums.py b/python/enums.py new file mode 100644 index 0000000..a53dc88 --- /dev/null +++ b/python/enums.py @@ -0,0 +1,71 @@ +import enum +from functools import total_ordering + + +@total_ordering +@enum.unique +class BaseUniqueSortedEnum(enum.Enum): + """Base unique enum class with ordering.""" + + def __new__(cls, *args, **kwargs): + obj = object.__new__(cls) + obj.index = len(cls.__members__) + 1 + return obj + + def __hash__(self) -> int: + return hash( + f"{self.__module__}_{self.__class__.__name__}_{self.name}_{self.value}" + ) + + def __eq__(self, other) -> bool: + self._check_type(other) + return super().__eq__(other) + + def __lt__(self, other) -> bool: + self._check_type(other) + return self.index < other.index + + def _check_type(self, other) -> None: + if type(self) != type(other): + raise TypeError(f"Different types of Enum: {self} != {other}") + + +class Dog(BaseUniqueSortedEnum): + BLOODHOUND = "BLOODHOUND" + WEIMARANER = "WEIMARANER" + SAME = "SAME" + + +class Cat(BaseUniqueSortedEnum): + BRITISH = "BRITISH" + SCOTTISH = "SCOTTISH" + SAME = "SAME" + + +assert Dog.BLOODHOUND < Dog.WEIMARANER +assert Dog.BLOODHOUND <= Dog.WEIMARANER +assert Dog.BLOODHOUND != Dog.WEIMARANER +assert Dog.BLOODHOUND == Dog.BLOODHOUND +assert Dog.WEIMARANER == Dog.WEIMARANER +assert Dog.WEIMARANER > Dog.BLOODHOUND +assert Dog.WEIMARANER >= Dog.BLOODHOUND + +assert Cat.BRITISH < Cat.SCOTTISH +assert Cat.BRITISH <= Cat.SCOTTISH +assert Cat.BRITISH != Cat.SCOTTISH +assert Cat.BRITISH == Cat.BRITISH +assert Cat.SCOTTISH == Cat.SCOTTISH +assert Cat.SCOTTISH > Cat.BRITISH +assert Cat.SCOTTISH >= Cat.BRITISH + +assert hash(Dog.BLOODHOUND) == hash(Dog.BLOODHOUND) +assert hash(Dog.WEIMARANER) == hash(Dog.WEIMARANER) +assert hash(Dog.BLOODHOUND) != hash(Dog.WEIMARANER) +assert hash(Dog.SAME) != hash(Cat.SAME) + +# raise TypeError +Dog.SAME <= Cat.SAME +Dog.SAME < Cat.SAME +Dog.SAME > Cat.SAME +Dog.SAME >= Cat.SAME +Dog.SAME != Cat.SAME