Exhaustive Checks with Mypy
To achieve exhaustive type checking on enums or literals with Mypy validation when a case is forgotten, you can implement a utility function:
from typing import NoReturn
def unreachable(v: NoReturn) -> NoReturn:
raise AssertionError()
The utility works with Python 3.10’s match statement or traditional is
comparisons:
import enum
from .utils import unreachable
class Fruit(enum.Enum):
APPLE = enum.auto()
BANANA = enum.auto()
def using_match(fruit: Fruit) -> int:
match fruit:
case Fruit.APPLE:
return 1
case Fruit.BANANA:
return 2
case _:
unreachable(fruit)
def using_is(fruit: Fruit) -> int:
if fruit is Fruit.APPLE:
return 1
elif fruit is Fruit.BANANA:
return 2
else:
unreachable(fruit)
This won’t work for enums when using equality operators, since Mypy cannot
determine if == has been overridden:
def using_eq(fruit: Fruit) -> int:
if fruit == Fruit.APPLE:
return 1
elif fruit == Fruit.BANANA:
return 2
else:
# error: Argument 1 to "unreachable" has incompatible
# type "Fruit"; expected "NoReturn" [arg-type]
unreachable(fruit)