Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Exhaustiveness checking util #735

Closed
Phlogistique opened this issue Jun 26, 2020 · 6 comments
Closed

Exhaustiveness checking util #735

Phlogistique opened this issue Jun 26, 2020 · 6 comments
Labels
topic: feature Discussions about new features for Python's type annotations

Comments

@Phlogistique
Copy link

There is a known idiom for ensuring exhaustiveness of an if chain:
python/mypy#5818

from typing import NoReturn

def assert_never(x: NoReturn) -> NoReturn:
    raise AssertionError(f"Invalid value: {x!r}")

from typing import Union

def type_checking_ok(foo: Union[str, int]) -> None:
    if isinstance(foo, str):
        print("str")
    elif isinstance(foo, int):
        print("int")
    else:
        assert_never(foo)

def type_checking_ko(foo: Union[str, int]) -> None:
    if isinstance(foo, str):
        print("str")
    else:
        assert_never(foo)

It works with mypy but I have not tested it with other type checkers.

Because it is not in the standard library, it has to be implemented or imported in many projects that use typing. At my workplace, we have this util under the name assert_exhaustivity

It would be helpful to document this idiom and have it in the standard library. Would a pull request to this repository be the right way to make it happen? Or does it need a PEP?

@gvanrossum
Copy link
Member

Maybe static type checkers could add support for assert False directly in this place? Then you wouldn't need the dummy function. Surely a static checker can deduce that assert False is intended to be unreachable?

@Phlogistique
Copy link
Author

One added advantage of the assert_never approach is that the type checker can print the type for the missing branch.

For example with mypy:

test.py:12: error: Argument 1 to "assert_never" has incompatible type "int"; expected "NoReturn"

@bluetech
Copy link

bluetech commented Jul 6, 2020

I think commandeering assert False would be really nice, however I suspect it wouldn't work well because there is a lot of code out there which uses assert False for unreachable sections which are not statically known to be unreachable.

@freundTech
Copy link

With Pattern Matching now being accepted into python there might be renewed interest in this topic.

I would suggest adding assert_exhaustive(x) to typing. The implementation could raise a fitting exception (Just assert False would of course also work, but I would argue that it's helpful to also give more details if it fails at runtime. Not only if it fails during type-checking).

Type-checkers can then just be hardcoded to handle assert_exhaustive(), which removes the problem with NoReturn only being allowed as a return type.

Type-checkers could also make sure that assert_exhaustive() is only used within else blocks (and maybe case _ blocks in the future.

PS: Starting in April I will be writing my bachelors thesis on the topic of "Exhaustiveness check for Structural Pattern Matching in Python 3.10". My work will most likely be based on mypy and I'm planing to contribute the code back to upstream. Having an "official" way to annotate exhaustiveness would be really useful for me.

@srittau srittau added the topic: feature Discussions about new features for Python's type annotations label Nov 4, 2021
@antonagestam
Copy link

Just as cross-reference for people following this issue: there's been some recent movement towards adding an assert_never() function to typing, as well as a new Never type that is identical to NoReturn but documented differently.

@Phlogistique
Copy link
Author

assert_never has been merged, closing this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
topic: feature Discussions about new features for Python's type annotations
Projects
None yet
Development

No branches or pull requests

6 participants