Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Modify enum.IntFlag __repr__

Tags:

python

enums

I have written a small utility that decodes log output consisting of bit-flags. I use enums when decoding those bit-flags.

python --version
Python 3.8.6

For brevity reasons, I only want to print the enumeration member name. I've distilled my problem down to this short snippet:

from enum import IntFlag
class Foo(IntFlag):
    A = 0x01
    B = 0x02
    C = 0x04
    def __str__(self):
        return self.name
    __repr__ = __str__

It works fine if I show them individually or if I print them as part of a list. But I can't print an or-expression. I want to display the flags on the form A|B|C.

>>> Foo.A
A
>>> Foo.B
B
>>> [Foo.A, Foo.B]
[A, C]
>>> Foo.A | Foo.B
TypeError: __repr__ returned non-string (type NoneType)

Update: I was looking at the wrong version of the source code. The IntFlag::__repr__ for the 3.8.6 tag does contain code that does print each member https://github.com/python/cpython/blob/v3.8.6/Lib/enum.py#L761

I tried reading CPythons Lib/enum.py but couldn't figure out how thedefault IntFlag (without my overriden __repr__) prints the output on the form Foo.A|Foo.B.~~

I can see that IntFlag.__or__ returns a new object by calling __class__ (I don't really know what __class__ does). And Enum.__repr__ just prints a single class name and enumeration name.

How do I write a __repr__ function and a __str__ function which returns a string representation of the enumeration member names that are currently set?

like image 350
Daniel Näslund Avatar asked Jan 27 '26 07:01

Daniel Näslund


1 Answers

from enum import Flag, _power_of_two

class BetterFlag(Flag):
    def __repr__(self):
        if self.value == 0:
            return "%s(0)" % self.__class__.__name__
        return '|'.join(
                m.name
                for m in self.__class__
                if m.value & self.value and _power_of_two(m.value)
                )
    __str__ = __repr__

Python 3.10 and earlier do this by testing if the name attribute is None, and if so then looping over the contents. The looping was flawed for more exotic enums, and has been redone in 3.11.

Note: The above is forwards and backwards compatible. Have your Flags inherit from BetterFlag.

like image 172
Ethan Furman Avatar answered Jan 29 '26 20:01

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!