Python Forum

Full Version: Return a string or byte object from Enum class?
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
I wish to have a class that simply contains some values. I want to avoid using the .value attribute. In other words I want to use "class.my_enum" to get a value instead of "class.my_enum.value".

I have the following code that will always return a string.

from enum import Enum

class TestClass(str, Enum):
    str_value = "abc"
    byte_value = "abc".encode('latin-1')
    
    def __str__(self):
        return str.__str__(self.value)
    

x = TestClass.str_value
print(x)
print(type(x))

x = TestClass.byte_value
print(x)
print(type(x))
This returns my values TestClass.str_value and TestClass.byte_value as an enum that works like a string. Unfortunately, I need TestClass.byte_value to be a bytes object.

Something like this would do what I want, except that this would allow the values in the class to be altered.

class TestClass():
    str_value = "abc"
    byte_value = "abc".encode('latin-1')


x = TestClass.str_value
print(x)
print(type(x))

x = TestClass.byte_value
print(x)
print(type(x))

# This should cause an error
TestClass.str_value = 5
print(TestClass.str_value)
How can I return different value types and disallow changing of their values?
It would be nice to have some context. How is this thing used (ideally)?

I don't know if this would be helpful
class String(enum.StrEnum):
    EENIE = "eenie"
    MEENIE = "meenie"
    MINY = "miney"
    MO = "mo"

    def __bytes__(self):
        return self.value.encode("utf8")


print(String.EENIE, type(String.EENIE), type(str(String.EENIE)), bytes(String.EENIE), type(bytes(String.EENIE)))
String is not a str or bytes, but it knows how to convert the enumeration to either.
Same code as above, but made it with a base class.
MyEnum inherits from StrBytesEnum which inherits from StrEnum.

from enum import StrEnum


class StrBytesEnum(StrEnum):
    def __bytes__(self):
        return self.value.encode("utf8")

class MyEnum(StrBytesEnum):
    EENIE = "eenie"
    MEENIE = "meenie"
    MINY = "miney"
    MO = "mo"


print(MyEnum.EENIE, type(MyEnum.EENIE), type(str(MyEnum.EENIE)), bytes(MyEnum.EENIE), type(bytes(MyEnum.EENIE)))
(May-13-2025, 08:40 PM)deanhystad Wrote: [ -> ]It would be nice to have some context. How is this thing used (ideally)?

We have a class that retrieves login credentials from a vault. Up until recently, the credentials we wanted would always be strings. We have a new credential that should be a bytes object and not a string. In our class we would pull an encoded phrase string from the the vault, decode it to a bytes object, then return it as an attribute. For consistency sake, we would like to avoid returning it as a string and then having to encode it (or eval it) to get the bytes object. We also do not want users to be able to overwrite the values returned by the class.

In the code below, we were using _str_ to return the value as a string and to avoid using the .value attribute. This is an issue, now that we want something other than a string returned.

from enum import Enum
import base64

class Credentials:

    class Server1(str, Enum):
        url = "auth.server1.com"
        username = "bob"
        password = "bobs_password"

        def __str__(self):
            return self.value
            
    class Server2(str, Enum):
        url = "api.server2.com"
        # "SomeEncodedPhraseFromTheVault"
        __phrase = b"U29tZUVuY29kZWRQaHJhc2VGcm9tVGhlVmF1bHQ="
        phrase = base64.b64decode(__phrase)

        def __str__(self):
            return self.value
            
# We want to fetch a string here
username = Credentials.Server1.username
login = username + "@server1.com"
print(login)

url2 = Credentials.Server2.url
passphrase = Credentials.Server2.phrase # <--- We want a bytes object here, not a string
print(passphrase)
passphrase = eval(passphrase) # This is how we are working around it for now
print(type(passphrase))
I'm thinking that forgetting about Enum and just using class attributes is the best answer. Users can deal with the issues if they end up overwriting one of the attributes.

class TestClass():
    str_value = "abc"
    byte_value = "abc".encode('latin-1')
Let me know if I'm missing something obvious.
(May-14-2025, 02:45 PM)Calab Wrote: [ -> ]'m thinking that forgetting about Enum and just using class attributes is the best answer.
Yes look like not needed in this task.
Could use a frozen @dataclass to get mixed‐type attributes plus immutability.
from dataclasses import dataclass
import base64

@dataclass(frozen=True)
class Server1:
    url: str = "auth.server1.com"
    username: str = "bob"
    password: str = "bobs_password"

@dataclass(frozen=True)
class Server2:
    url: str = "api.server2.com"
    # store your vault‐decoded bytes in the dataclass
    phrase: bytes = base64.b64decode(b"U29tZUVuY29kZWRQaHJhc2VGcm9tVGhlVmF1bHQ=")

# usage:
s1 = Server1()
print(s1.username)

s2 = Server2()
print(s2.phrase, type(s2.phrase))

# immutable:
s2.phrase = b"foo"
Output:
bob b'SomeEncodedPhraseFromTheVault' <class 'bytes'> Traceback (most recent call last): File "<module2>", line 24, in <module> File "<string>", line 16, in __setattr__ dataclasses.FrozenInstanceError: cannot assign to field 'phrase'