The short version is that I have a Flag where every member (save one) should have a corresponding composite member of its value ORed with a special nonmember flag. Example:
from enum import Flag, auto, nonmember # new in 3.11
class Planet(Flag):
_BIZARRO = nonmember(1) # flag to denote other version
SUN = 0 # no bizarro version
MERCURY = 2 # need to start with 2 to avoid _BIZARRO
VENUS = auto() # auto works from here
EARTH = auto()
MARS = auto()
BIZARRO_MERCURY = MERCURY | _BIZARRO
BIZARRO_VENUS = VENUS | _BIZARRO
BIZARRO_EARTH = EARTH | _BIZARRO
BIZARRO_MARS = MARS | _BIZARRO
@property
def BIZARRO(self):
if self is Planet.SUN:
return self
return Planet(self.value ^ Planet._BIZARRO)
# for nicer display
def __repr__(self):
return self.name
This is handy because it allows for stuff like
(
Planet.MARS.BIZARRO,
Planet.VENUS.BIZARRO is Planet.BIZARRO_VENUS,
Planet.EARTH.BIZARRO.BIZARRO is Planet.EARTH,
)
outputs:
(BIZARRO_MARS, True, True)
Which, in my (non-bizarro) application, makes a lot of stuff easier.
Can I define a subclass that would build this for me? I’d call MyEnum("Planet", ["VENUS", "MERCURY", "EARTH", "MARS"]
and it produces a Flag with the above behavior, including the names. That’d save some boilerplate, and allow me to specify the list in a config if I wanted to.
I can avoid defining the composite types if I use boundary=KEEP
, but that’s not quite ideal. It doesn’t display things nicely unless I customize __repr__
more, and the additional types aren’t available as members.
I’ve been reading through the Enum docs for a while, trying to figure out if this is possible. It feels like I should be able to subtype Enum
or more likely EnumType
to make this happen. But the level of metaprogramming is too much for me at the moment, so I figured I’d toss it out here.