diff --git a/docs/source/literal_types.rst b/docs/source/literal_types.rst index a223011effe94..216313b6c20e2 100644 --- a/docs/source/literal_types.rst +++ b/docs/source/literal_types.rst @@ -289,6 +289,73 @@ using ``isinstance()``: This feature is sometimes called "sum types" or "discriminated union types" in other programming languages. +Exhaustive checks +***************** + +One may want to check that some code covers all possible ``Literal`` or ``Enum`` cases, +example: + +.. code-block:: python + + from typing import Literal + + PossibleValues = Literal['one', 'two'] + + def validate(x: PossibleValues) -> bool: + if x == 'one': + return True + elif x == 'two': + return False + raise ValueError('Wrong values passed: {0}'.format(x)) + + assert validate('one') is True + assert validate('two') is False + +In the code above it is really easy to make a mistake in the future: +by adding a new literal value to ``PossibleValues``, +but not adding its handler to ``validate`` function: + +.. code-block:: python + + PossibleValues = Literal['one', 'two', 'three'] + +Mypy won't catch that ``'three'`` is not covered. +However, if you want to have exhaustive check, you need to guard it properly: + +.. code-block:: python + + from typing import Literal, NoReturn + + PossibleValues = Literal['one', 'two'] + + def assert_never(value: NoReturn) -> NoReturn: + # This also works in runtime as well: + assert False, 'This code should never be reached, got: {0}'.format(value) + + def validate(x: PossibleValues) -> bool: + if x == 'one': + return True + elif x == 'two': + return False + assert_never(x) + +In this case, when adding new values to ``PossibleValues``: + +.. code-block:: python + + PossibleValues = Literal['one', 'two', 'three'] + +Mypy will cover you: + +.. code-block:: python + + def validate(x: PossibleValues) -> bool: + if x == 'one': + return True + elif x == 'two': + return False + assert_never(x) # E: Argument 1 to "assert_never" has incompatible type "Literal['three']"; expected "NoReturn" + Limitations ***********