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`
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
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`
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