Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Create an Enum using a custom mix-in type

Tags:

python

oop

enums

In the relevant section of the Python Enum documentation, it is mentioned that mix-in types can be used to ensure items belong to that type and act as objects of that type, like in the example:

class IntEnum(int, Enum):
    pass

However, the documentation does not give any examples on how to use a custom class as a mix-in type, and I've failed miserably at that. Is it even possible? And if so, how do I do it?


The code I'm trying to write is

@dataclass
class Field:
    dtype: str
    name: str

@dataclass
class FwfField(Field):
    width: int

    def __post_init__(self):
        if self.width <= 0:
            raise ValueError("Field width must be positive.")

class CnefeSchema(FwfField, Enum):
    state_code = ("int", "Código da UF", 2)
    ...

When I import CnefeSchema from another file or run it, I get

---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
Input In [1], in <cell line: 1>()
----> 1 from src.conf.schemas import CnefeSchema

File src/conf/schemas.py:25, in <module>
     21     pass
     24 # TODO automatically read schema from Layout
---> 25 class CnefeSchema(EnumFwfField, Enum):
     27     @classmethod
     28     def parse(cls) -> tuple[list, dict, dict]:
     29         """
     30         Get field widths, dtypes, and columns from schema.
     31
   (...)
     34         as `pandas.read_fwf`.
     35         """

File /usr/lib/python3.10/enum.py:298, in EnumMeta.__new__(metacls, cls, bases, classdict, **kwds)
    296 enum_member._name_ = member_name
    297 enum_member.__objclass__ = enum_class
--> 298 enum_member.__init__(*args)
    299 # If another member with the same value was already defined, the
    300 # new member becomes an alias to the existing one.
    301 for name, canonical_member in enum_class._member_map_.items():

File <string>:4, in __init__(self, dtype, name, width)

File /usr/lib/python3.10/types.py:187, in DynamicClassAttribute.__set__(self, instance, value)
    185 def __set__(self, instance, value):
    186     if self.fset is None:
--> 187         raise AttributeError("can't set attribute")
    188     self.fset(instance, value)

AttributeError: can't set attribute

I've already tried:

  • Defining another class, EnumFwfField, and using it as a mix-in, i.e.
    class EnumFwfField(FwfField, Enum):
        pass
    
    class CnefeSchema(EnumFwfField, Enum):
        ...
    
    but I get the same error as above;
  • Setting the Enum fields (in this example, state_code) to FwfField, i.e.
    class CnefeSchema(FwfField, Enum):
        state_code = FwfField("int", "Código da UF", 2)
        ...
    
    but then I get
    Traceback (most recent call last):
      File "src/conf/schemas.py", line 25, in <module>
        class CnefeSchema(EnumFwfField, Enum):
      File "/usr/lib/python3.10/enum.py", line 298, in __new__
        enum_member.__init__(*args)
    TypeError: FwfField.__init__() missing 2 required positional arguments: 'name' and 'width'
    
like image 373
tomaz-suller Avatar asked Mar 21 '26 04:03

tomaz-suller


1 Answers

The issue you are having is because in your above code you have a name attribute in your Field dataclass, but Enum will not let you set a name attribute.

Rename that field to something else, for example 'dname', and it should work.

(The error message in 3.11 is more informative.)

like image 171
Ethan Furman Avatar answered Mar 22 '26 18:03

Ethan Furman



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!