Enum for bitwise operations with user readable strings table

181 Views Asked by At

I am looking for an efficient and maintainable way to create a table in Python that can be used to look up user readable strings for enumeration values.

Constraints:

  • I want it to work with an enumeration that supports bitwise operations. For example: passing in a value of enumeration values that has been bitmasked together will return a list of strings for each bitmasked value.
  • I want the user readable strings to be translated from the enumeration value names so I don't have to maintain a table that has to be updated every time the enumeration is modified.
  • I want it to be efficient. For example, I don't want a static function that will do the conversion every time it's called. I want to create a static table that is initialized once with the strings. For Example, I want to create a static dict that looks like this: {Privileges.CanAddPost: "can add post", Privileges.CanDeletePost: "can delete post", ...}
from enum import IntFlag, unique

@unique
class Privileges(IntFlag):
    """Privileges enum that supports bitwise operations"""
    NoPrivileges = 0
    CanAddPost = 1
    CanDeletePost = 2
    CanBanUser = 4
    CanResetPasswords = 8
    CanModerateDiscussions = 16
    CanSuspendAccounts = 32
    All = CanAddPost | CanDeletePost | CanBanUser |\
        CanResetPasswords | CanModerateDiscussions | CanSuspendAccounts

#Instantiate the static variable
Privileges.strings_map = ...  # How do initialize this table?
1

There are 1 best solutions below

2
tdemay On BEST ANSWER

To accomplish this I created two functions. The first is a static function _toString(privilege) that will convert a enumeration value name to a user readable string. For example: CanAddPost becomes "can add post"

The 2nd function list_privileges() converts a bitmask of enumeration values to a list of strings. For Example: Privileges.CanAddPost|Privileges.CanDeletePost becomes ["can add post", "can delete post"]

I use a dictionary comprehension to create a static string_map lookup table.

from enum import IntFlag, unique

@unique
class Privileges(IntFlag):
    """Privileges enum that supports bitwise operations"""
    NoPrivileges = 0
    CanAddPost = 1
    CanDeletePost = 2
    CanBanUser = 4
    CanResetPasswords = 8
    CanModerateDiscussions = 16
    CanSuspendAccounts = 32
    All = CanAddPost | CanDeletePost | CanBanUser |\
        CanResetPasswords | CanModerateDiscussions | CanSuspendAccounts

    @staticmethod
    def _toString(privilege) -> str:
        """Converts a Privileges enum value to a string"""
        return "".join([char if char.islower() else " " + char.lower()\
                        for char in privilege.name]).lstrip()

    def list_privileges(self) -> list:
        """Converts a bitmask of Privileges to a list of readable strings"""
        return list(\
                [Privileges.strings_map[privilege] for privilege in Privileges\
                    if privilege != Privileges.NoPrivileges\
                        and privilege != Privileges.All\
                        and (privilege & self) == privilege])

# Create static strings_map that will map a Privilege enum value to a 
#   readable string
Privileges.strings_map = { privilege: Privileges._toString(privilege) for privilege in Privileges}

user_privileges = Privileges.CanAddPost | Privileges.CanDeletePost
admin_privileges = Privileges.All

print(user_privileges.list_privileges())
print(admin_privileges.list_privileges())

Output:

['can add post', 'can delete post']
['can add post', 'can delete post', 'can ban user', 'can reset passwords', 'can moderate discussions', 'can suspend accounts']