IntEnum literals are not considerable comparable with ints
Bug Report
The handling of types for IntEnum literals shows no overlap with int literals.
The handling for int variables appears to be correct,
To Reproduce
from enum import IntEnum
class CardVal(IntEnum):
VAL_A = 1
VAL_2 = 2
try:
assert CardVal.VAL_A == 1
except AssertionError:
pass # So we see the second error in mypy
assert CardVal.VAL_2 == 2
Expected Behavior
The type of CardVal.VAL_A gets erased to something considered comparable to Literal[1]
Actual Behavior
From the playground link, using python 3.10 / mypy 1.6.1:
main.py:9: error: Non-overlapping equality check (left operand type: "Literal[CardVal.VAL_A]", right operand type: "Literal[1]") [comparison-overlap]
main.py:13: error: Non-overlapping equality check (left operand type: "Literal[CardVal.VAL_2]", right operand type: "Literal[2]") [comparison-overlap]
Found 2 errors in 1 file (checked 1 source file)
The same behaviour has been seen locally with python 3.11 / mypy 1.6.1
I think this is a special case of https://github.com/python/mypy/issues/17317.
I would agree and will close this in favour of #17317
#17317 concerns members accessed from enum instance (self == self.SOMETHING) and passes if we use EnumClass.SOMETHING instead. This is not a duplicate - some_int_enum == some_int is not the same as some_enum == some_enum.OTHER_FIELD.
The same issue happens when using StrEnums.
To reproduce: playground
import enum
from typing import Literal
class MyEnum(enum.StrEnum):
A = 'a'
def compare(value: Literal['a', 'b']) -> bool:
if value == MyEnum.A: # generates a 'Non-overlapping equality check' error
return True
return False
def compare_str(value: str) -> bool:
if value == MyEnum.A: # does not generate an error
return True
return False
I hoped this to be solved after #10910 but apparently there's more to it. It would seem to me as if an IntEnum should be exchangeable with a union of literal ints. It is not and Mypy main (as of db67fac952a390cf2cb533beb9bcce1cf15ce918) reports an error:
import enum
from typing import Literal
type One = Literal[1]
type Two = Literal[2]
type Three = Literal[3]
def option(arg: One | Two | Three) -> None:
...
class MyEnum(enum.IntEnum):
ONE = 1
TWO = 2
THREE = 3
option(MyEnum.TWO) # error: Argument 1 to "option" has incompatible type "Literal[MyEnum.TWO]"; expected "Literal[1, 2, 3]" [arg-type]