How to type Enum created dynamically with a default value?

Question:

Using the Functional API
I want to type my enum so it would have a default known value.

Example:

class MyBaseClass:
    ...

class DerivedA(MyBaseClass):
    ...

class DerivedB(MyBaseClass):
    ...

DerivedChoice = enum.Enum('DerivedChoice', {cls.__name__: cls for cls in (DerivedA, DerivedB)})


foo: DerivedChoice = DerivedChoice.DerivedB

foo.value  # <- this should be  `MyBaseClass`
Asked By: Nr Bnlullu

||

Answers:

Here is a nice and hacky solution

T = TypeVar('T')

if TYPE_CHECKING:
    class DefaultEnum(Generic[T], enum.Enum):  # this class does not exist at runtime
        @property
        def value(self) -> T:
            ...

def default_enum(name: str, members: dict[str, T], type: T) -> 'DefaultEnum[T]':
    return enum.Enum(name, members)  # type: ignore

Usage:

class MyBase:
    foo: int
    bar: str


class A(MyBase):
    ...


class B(MyBase):
    ...

MyBaseDerived = default_enum(name='MyBaseDerived',
                             members={cls.__name__: cls for cls in (A, B)},
                             type=MyBase)

MyBaseDerived.value.foo  # <- hinted by PyCharm 

Edit:

This one seems to work on VSCode

from typing import Generic, TypeVar, TYPE_CHECKING
import enum

T = TypeVar('T')

if TYPE_CHECKING:
    from dataclasses import dataclass


    class EnumProperty(Generic[T]):
        name: str
        value: T


    class DefaultEnum(Generic[T]):  # this class does not exist at runtime
        def __getattribute__(self, item) -> 'EnumProperty[T]':
            ...


def default_enum(name: str, members: dict[str, T], type: T) -> 'DefaultEnum[T]':
    return enum.Enum(name, members)  # type: ignore

Answered By: ניר
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.