Python mypy warning of incompatible type when using Enum Flag

Question:

I am trying to make a variable that can be from a set of enum values, and then select a specific one when using it elsewhere.

from enum import Flag, auto


class MyEnum(Flag):
    FOO: int = auto()
    BAR: int = auto()
    MOO: int = auto()


def use_enum(my_enum: MyEnum) -> None:
    print(my_enum)


if __name__ == "__main__":
    any_enum: MyEnum = MyEnum.FOO | MyEnum.BAR
    print(type(any_enum.FOO))
    use_enum(my_enum=any_enum.FOO)  # Argument "my_enum" to "use_enum" has incompatible type "int"; expected "MyEnum"  [arg-type]mypy(error)

However the output shows:

<enum 'MyEnum'>
MyEnum.FOO

Is this a false positive from mypy?

Is there a different way this can be done so that any_enum can be used to suggest a subset from MyEnum?

Asked By: PepsiBandit

||

Answers:

mypy’s either doing something wrong when accessing enum members from enum instances, or maybe (as the comments have pointed out) mypy is just deciding to conform with the deprecation of such an access.

When you access a class-level variable from an instance of MyEnum (e.g. MyEnum.BAR), mypy thinks the variable’s type is whatever’s annotated or inferred on the class body (which is technically true for other kinds of classes):

class MyEnum(Flag):
    FOO: int = auto()
    BAR: int = auto()
    MOO: int = auto()

>>> # mypy is correct here
>>> reveal_type(MyEnum.FOO)  # mypy: Revealed type is "Literal[error.MyEnum.FOO]?"
>>> # Based on the runtime implementation,
>>> # this should still be "Literal[error.MyEnum.FOO]?"
>>> reveal_type(MyEnum.FOO.FOO)  # mypy: Revealed type is "builtins.int"

But yeah, I don’t think it’s good practice to refer to enum members from the instance; although you technically can access any enum member through an enum instance like MyEnum.FOO.BAR.MOO.FOO at runtime, this is bad code in practice.

Answered By: dROOOze
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.