Add docstrings to Python Enum members

gui commited 2 months ago · 🐍 Python

Recently I learned that Python Enum members don't "support" docstrings natively which is quite annoying.

I had to manage a list of feature flags and provide a good description for each of them through FastAPI:

from enum import StrEnum, auto

class FeatureFlag(StrEnum):
    """Holds a list of available feature toggles"""
    
    ENABLE_CHAT_GPT = auto()
    """Requested by a few customers to enable Chat GPT within the app"""
    
    DARK_MODE = auto()
    """Fixes your color schema"""
    

Python Enum member docstring limitation

To my surprise when I extracted each member's __doc__ (which should contain the docstring) I got the FeatureFlag class docstring instead.

print(FeatureFlag.ENABLE_CHAT_GPT.__doc__) # ❌ output: Holds a list of available feature toggles

print(FeatureFlag.DARK_MODE.__doc__) # ❌ output: Holds a list of available feature toggles

This is definitively not what we expect. We want the enum member's docstring.

How to add docstring to enum members?

The best solution I could come up with is to override the __new__ method and require members to take two string values:

from enum import StrEnum, auto
import typing as t


class FeatureFlag(StrEnum):
    """Holds a list of available feature toggles"""
    
    # 👇 Magic method needed to enforce members to take docstrings
    def __new__(cls, value: str, docstr: str) -> t.Self:
        member = str.__new__(cls, value)

        member._value_ = value
        member.__doc__ = docstr.strip()  # 🪄 Magic

        return member


    ENABLE_CHAT_GPT = (auto(), """Requested by a few customers to enable Chat GPT within the app""")
        
    DARK_MODE = (auto(), """Fixes your color schema""")
    

print(FeatureFlag.ENABLE_CHAT_GPT.__doc__) # ✅ output: Requested by a few customers to enable Chat GPT within the app
print(FeatureFlag.DARK_MODE.__doc__) # ✅ output: Fixes your color schema

This might not be the cleanest, but it works and it's simple to maintain.

Now I can iterate over the enum members and take each "docstring":

flags = [dict(key=flag.value, description=flag.__doc__) for flag in FeatureFlags]
print(flags)

# outputs:
# [
#  {'key': 'enable_chat_gpt', 'description': 'Requested by a few customers to enable Chat GPT within the app'}, 
# {'key': 'dark_mode', 'description': 'Fixes your color schema'}
#]
  • LinkedIn
  • Tumblr
  • Reddit
  • Google+
  • Pinterest
  • Pocket