mypy icon indicating copy to clipboard operation
mypy copied to clipboard

IntEnum literals are not considerable comparable with ints

Open javajawa opened this issue 2 years ago • 4 comments

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

playground

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

javajawa avatar Oct 25 '23 19:10 javajawa

I think this is a special case of https://github.com/python/mypy/issues/17317.

bersbersbers avatar Jun 03 '24 09:06 bersbersbers

I would agree and will close this in favour of #17317

javajawa avatar Jun 16 '24 14:06 javajawa

#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.

sterliakov avatar Apr 05 '25 02:04 sterliakov

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

sk- avatar Jun 13 '25 12:06 sk-

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]

ambv avatar Aug 05 '25 17:08 ambv