mypy
mypy copied to clipboard
False positive for "Non-overlapping identity check" when comparing Enum variants
Bug Report
I think I've uncovered a false positive in mypy's type-checking of is operator with Enums. See below for details.
I know that Enums are a bit funky, so it's possible this is expected behavior (actually, there's a related bug report here https://github.com/python/mypy/issues/9817).
To Reproduce
# test.py
from enum import Enum
class Food(Enum):
SPAM = "spam"
HAM = "ham"
def is_spam(self) -> bool:
return self is self.SPAM
print(Food.SPAM.is_spam())
print(Food.HAM.is_spam())
$ python3 test.py
True
False
$ mypy test.py
test.py: note: In member "is_spam" of class "Food":
test.py:8:16: error: Non-overlapping identity check (left operand type: "Food", right operand type: "str")
[comparison-overlap]
return self is self.SPAM
^
Found 1 error in 1 file (checked 1 source file)
This goes away if I write it as
def is_spam(self) -> bool:
return self is Food.SPAM
though I'd like to avoid having to duplicate the name of the class a bunch of times in methods with lots of branching on the variant.
Your Environment
$ mypy --version
mypy 0.910
$ cat .mypy.ini
[mypy]
# https://mypy.readthedocs.io/en/stable/index.html
python_version = 3.6
pretty = True
show_column_numbers = True
show_error_codes = True
show_error_context = True
check_untyped_defs = True
disallow_any_generics = True
disallow_incomplete_defs = True
disallow_subclassing_any = True
disallow_untyped_calls = True
disallow_untyped_decorators = True
disallow_untyped_defs = True
no_implicit_optional = True
no_implicit_reexport = True
strict_equality = True
warn_redundant_casts = True
warn_return_any = True
warn_unused_configs = True
warn_unused_ignores = True
$ python3 --version
Python 3.6.9
$ lsb_release -ds
Ubuntu 18.04.5 LTS
Same problem in this code:
#!/usr/bin/env -S uv run --script --python 3.13
from enum import Enum
class Animals(Enum):
CAT = "cat"
DOG = "dog"
BIRD = "bird"
@property
def is_mammal(self) -> bool:
# Mypy is confused about the type of the properties when
# reference via `self.`, it considers them as it would a
# variable on any other class, and if it was just a variable on
# a non-enum class, the type of `self.DOG` would be `str`, not
# `Animals`. So it reports an this error:
# error: Non-overlapping container check (element type: "Animals", container item type: "str")
return self in {self.CAT, self.DOG}
class Vehicle(Enum):
AEROPLANE = "aeroplane"
CAR = "car"
HELICOPTER = "helicopter"
@property
def is_airborne(self) -> bool:
# Explicitly getting the type of `self` and then accessing the enum members via the class
# avoids the mypy error, as it knows that `type(self).AIRPLANE` is of type `Vechicle` and not `str`.
cls = type(self)
return self in {cls.AEROPLANE, self.HELICOPTER}
def main() -> None:
for animal in Animals:
print(f"{animal = } {animal.is_mammal = }")
for vehicle in Vehicle:
print(f"{vehicle = } {vehicle.is_airborne = }")
if __name__ == "__main__":
main()
Commands:
# run type checking with mypy
uv tool run --from mypy==1.16.0 mypy --strict mypy_enum_property_self.py
# run the script with Python 3.13
uv run --script --python 3.13 mypy_enum_property_self.py
Results:
$ uv tool run --from mypy==1.16.0 mypy --strict mypy_enum_property_self.py
mypy_enum_property_self.py:21: error: Non-overlapping container check (element type: "Animals", container item type: "str") [comparison-overlap]
Found 1 error in 1 file (checked 1 source file)
$ uv run --script --python 3.13 mypy_enum_property_self.py
animal = <Animals.CAT: 'cat'> animal.is_mammal = True
animal = <Animals.DOG: 'dog'> animal.is_mammal = True
animal = <Animals.BIRD: 'bird'> animal.is_mammal = False
vehicle = <Vehicle.AEROPLANE: 'aeroplane'> vehicle.is_airborne = True
vehicle = <Vehicle.CAR: 'car'> vehicle.is_airborne = False
vehicle = <Vehicle.HELICOPTER: 'helicopter'> vehicle.is_airborne = True