False-positive "Non-overlapping equality check" comparing `Enum`s `self` to members
Bug Report
mypy does not understand that in an Enum, self can be compared to its members.
To Reproduce
from enum import Enum, auto
class Glass(Enum):
HALF_FULL = auto()
HALF_EMPTY = auto()
def print(self) -> str:
if self == self.HALF_FULL:
print("half full")
return
raise ValueError("Glass is not half-full.")
# prints "half full"
Glass.HALF_FULL.print()
https://mypy-play.net/?mypy=latest&python=3.12&flags=strict&gist=edf65b45f562ed246f05592cc02f1fda
Expected Behavior
No error.
Actual Behavior
main.py:9: error: Non-overlapping equality check (left operand type: "Glass", right operand type: "auto") [comparison-overlap]
Found 1 error in 1 file (checked 1 source file)
Your Environment
- Mypy version used: 1.10.0
- Mypy command-line flags:
--strict - Mypy configuration options from
mypy.ini(and other config files): none - Python version used: 3.12.3
https://github.com/python/mypy/issues/16327 seems related.
I would like to add an issue I encountered that appears related to this issue. Mypy creates a similar false positive "non-overlapping equality check" when an Enum that is a field of a class is modified by some method that is run on that class. I've added a minimal example below:
To Reproduce:
from enum import Enum
class SWITCH(Enum):
ON = 1
OFF = 0
class SwitchFlipper:
def __init__(self, enum_value: SWITCH):
self.enum_value = enum_value
def flip_switch(self) -> None:
if self.enum_value == SWITCH.ON:
self.enum_value = SWITCH.OFF
else:
self.enum_value = SWITCH.ON
flipper = SwitchFlipper(SWITCH.OFF)
assert flipper.enum_value == SWITCH.OFF
flipper.flip_switch()
assert flipper.enum_value == SWITCH.ON
Expected Behavior
No error.
Actual Behavior
error: Non-overlapping equality check (left operand type: "Literal[SWITCH.OFF]", right operand type: "Literal[Switch.ON]") [comparison-overlap]
My Environment:
Mypy version used: >=1.4.0 (issue does not show up in version 1.3.0 or earlier)
Mypy command-line flags: --strict
Mypy configuration options from mypy.ini (and other config files): none
Python version used: 3.8.10
Minimal Reproducible Example
from enum import Enum
class State(Enum):
IDLE = 0
RUNNING = 1
class Worker:
def __init__(self: "Worker") -> None:
self.state = State.IDLE
def run(self: "Worker") -> None:
self.state = State.RUNNING
class TestWorker:
def test_state(self: "TestWorker") -> None:
worker = Worker()
assert worker.state == State.IDLE
worker.run()
assert worker.state == State.RUNNING
Expected Behaviour
$ mypy mre.py --strict
Success: no issues found in 1 source file
Actual Behaviour
$ mypy mre.py --strict
mre.py:19: error: Non-overlapping equality check (left operand type: "Literal[State.IDLE]", right operand type: "Literal[State.RUNNING]") [comparison-overlap]
Found 1 error in 1 file (checked 1 source file)
Environment
$ mypy --version
mypy 1.11.2 (compiled: yes)
+1
Same for me
class TochkaDocumentType:
BENEFICIARY = 'beneficiary'
DEAL = 'deal'
@dataclass
class TochkaUploadDocumentEntity:
doc_type: TochkaDocumentType
beneficiary_id: str
deal_id: str | None
upload_message: TochkaUploadDocumentEntity = message
if upload_message.doc_type == TochkaDocumentType.DEAL:
The error:
error: Non-overlapping equality check (left operand type: "TochkaDocumentType", right operand type: "str") [comparison-overlap]
Mypy version
mypy 1.13.0 (compiled: yes)
@verhovensky I think your issue there is that your TochkaDocumentType does not extend Enum, so mypy is correct in observing that you are comparing an object of type TochkaDocumentType to a field of type str.
@TomHKeysight You are right, my bad After inheriting from StrEnum - the error is gone
Please note that the narrowing issue reported by @TomHKeysight and @arthurazs is completely irrelevant to the OP and is tracked in #17537. This ticket itself is a duplicate of #10910 modulo is vs ==.