Closed
Description
Bug Report
I have an Enum using function Enum API on external data (hence the functional API) with custom class (also according by docs) and I encountered a series of errors with mypy. I was able to mitigate several of them by a workaround, but I'm not able to solve one at the class level.
To Reproduce
from enum import Enum
_ANIMALS = {
'ANT': (0, 'Ant'),
'BEE': (1, 'Bee'),
'CAT': (2, 'Cat'),
'DOG': (3, 'Dog'),
}
class LabeledEnum(int, Enum):
def __new__(cls, value: int, label: str):
"""Construct item with label."""
obj = super().__new__(cls, value)
obj._value_ = value
obj.label = label
return obj
label: str
Animal = LabeledEnum('Animal', _ANIMALS)
def get_animal() -> Animal:
return Animal.ANT
Animal(3)
Expected Behavior
Ideally no errors. At least keep the information that LabeledEnum
is a type and not variable. That would require to ignore the valid-type
error at every usage in annotations of function arguments or return type.
Actual Behavior
error: Incompatible types in assignment (expression has type "int", variable has type "str") [assignment]
error: Argument 1 to "LabeledEnum" has incompatible type "str"; expected "int" [arg-type]
error: Argument 2 to "LabeledEnum" has incompatible type "Dict[str, Tuple[int, str]]"; expected "str" [arg-type]
error: Variable "custom_enum.Animal" is not valid as a type [valid-type]
note: See https://mypy.readthedocs.io/en/latest/common_issues.html#variables-vs-type-aliases
error: "LabeledEnum" has no attribute "ANT" [attr-defined]
error: "LabeledEnum" not callable [operator]
Workaround
I was able to mitigate most of the errors by ignores and overrides:
class LabeledEnum(int, Enum):
def __new__(cls, value: int, label: str):
"""Construct item with label."""
obj = super().__new__(cls, value)
obj._value_ = value # type: ignore[assignment]
obj.label = label
return obj
label: str
# mypy doesn't detect enum items, if generated dynamically.
# Define __getattribute__ to mask that.
def __getattribute__(self, name: str) -> 'LabeledEnum':
return super().__getattribute__(name)
# Call is not visible to mypy :-/
def __call__(self, *args, **kwargs) -> 'LabeledEnum':
return super().__call__(*args, **kwargs) # type: ignore[misc]
Animal = LabeledEnum('Animal', _ANIMALS) # type: ignore[arg-type]
but mypy still complain about the valid-type
when Animal
is used in function argument/return value.
Your Environment
- Mypy version used:0.812
- Mypy command-line flags: --show-error-codes (doesn't affect the error)
- Mypy configuration options from
mypy.ini
(and other config files): None - Python version used: 3.9.2