EQLTThatcher
EQLTThatcher

Reputation: 33

How to define __new__ for Enum subclasses?

I have a case where I have digit-only code values and some associated standard text. I have a number of fixed code sets I would like to define as enumerations where I can reuse the __new__ method that attaches the associated text to the members (I am using json to dump these, so want the serialization to reflect the value and not the text), but I am unable to get it work.

Here is my attempt:

import enum

class Code(str):
    def __new__(cls, code: str) -> None:
        if not code.isdigit():
            raise ValueError("code must be digits")
        return str.__new__(cls, code)

class CodeEnum(Code, enum.Enum):
    def __new__(cls, code: str, text: str) -> None:
        obj = Code.__new__(cls, code)
        obj._value_ = str(obj)
        obj.text = text
        return obj

class CodeSet1(CodeEnum):
    CODE_0001 = "0001", "Code 0001"

However, I get an AttributeError:

AttributeError: 'CodeSet1' object has no attribute '_name_'. Did you mean: 'name'?

Is there a way to resolve this such that I can reuse the __new__ method in CodeEnum for each of my code sets?

Upvotes: 3

Views: 711

Answers (1)

Ethan Furman
Ethan Furman

Reputation: 69041

The proper definition for CodeEnum is:

class CodeEnum(Code, enum.Enum):
    def __new__(cls, code: str, text: str) -> None:
        obj = super().__new__(cls, code)
        obj._value_ = Code(code)
        obj.text = text
        return obj

The major difference is using super(). _value_ is a Code instead of just a str because it should be the same core type as the enum itself.


Upvotes: 2

Related Questions