Skip to content

4 - Exhaustiveness checking with mypy

This technique is handy if there’s logic which should explicitly handle all possible values of an enumeration. With the example, mypy would kindly hint that BLUE is unhandled:

example.py 17: error: Argument 1 to "assert_never" has incompatible type "Literal[Color.BLUE]"; expected "NoReturn"

In addition to Enums, works great with e.g. Unions and Literals!

Exhaustiveness checking

Read more

This is a widely known trick but I assume the original credits belong to https://github.com/python/mypy/issues/5818.

More on the topic in the mypy docs: https://mypy.readthedocs.io/en/stable/literal_types.html#exhaustiveness-checks

The code
from enum import Enum
from typing import NoReturn


class Color(Enum):
    RED = "RED"
    GREEN = "GREEN"
    BLUE = "BLUE"  # I just added this


def handle_color(color: Color) -> None:
    if color is Color.RED:
        ...
    elif color is Color.GREEN:
        ...
    else:
        assert_never(color)


def assert_never(value: NoReturn) -> NoReturn:
    assert False, f"Unknown value: {value}"