Skip to content

Preferred idiom for exhaustiveness checking of unions #5818

Closed
@bluetech

Description

@bluetech
  • Are you reporting a bug, or opening a feature request?

A question...

  • Please insert below the code you are checking with mypy.

I have some union, e.g.

from typing import Union

MyUnion = Union[int, str]

and I have a function which takes the union and matches on it:

def handle_my_union(x: MyUnion) -> None:
    if isinstance(x, int): ...
    elif isinstance(x, str): ...

Now suppose that the union gets added a new member:

- MyUnion = Union[int, str]
+ MyUnion = Union[int, str, bytes]

I have to remember to add it to all of the places which match on the union, for example handle_my_union. As written above, mypy doesn't warn (and has no reason to). So what I use is this function (stolen mostly verbatim from TypeScript):

from typing import NoReturn

def assert_never(x: NoReturn) -> NoReturn:
    assert False, "Unhandled type: {}".format(type(x).__name__)

and use it as follows:

 def handle_my_union(x: MyUnion) -> None:
     if isinstance(x, int): ...
     elif isinstance(x, str): ...
+    else:
+        assert_never(x)
  • What is the actual behavior/output?

Now mypy warns:

error: Argument 1 to "assert_never" has incompatible type "bytes"; expected "NoReturn"

When I add a branch to handle bytes:

 def handle_my_union(x: MyUnion) -> None:
     if isinstance(x, int): ...
     elif isinstance(x, str): ...
+    elif isinstance(x, bytes): ...
     else:
         assert_never(x)

the error is gone.

  • What is the behavior/output you expect?

I am happy with this solution, I just wonder if this is something that is considered appropriate to rely on, or if there's another preferable way to achieve exhaustiveness checking?

  • What are the versions of mypy and Python you are using?

Python 3.5.5, mypy 0.630.

  • What are the mypy flags you are using? (For example --strict-optional)

no_implicit_optional, check_untyped_defs, warn_unused_ignores.

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions