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

Open
Phlogistique opened this issue Jun 26, 2020 · 5 comments
Open

Exhaustiveness checking util #735

Phlogistique opened this issue Jun 26, 2020 · 5 comments

Comments

@Phlogistique
Copy link

@Phlogistique Phlogistique commented Jun 26, 2020

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

@gvanrossum gvanrossum commented Jul 3, 2020

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

@Phlogistique Phlogistique commented Jul 6, 2020

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 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

@freundTech freundTech commented Mar 3, 2021

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.

petersaalbrink pushed a commit to petersaalbrink/apollo that referenced this issue Oct 19, 2021
Utility for exhaustiveness checking. See python/typing#735
petersaalbrink pushed a commit to petersaalbrink/apollo that referenced this issue Oct 19, 2021
Utility for exhaustiveness checking. See python/typing#735
@antonagestam
Copy link

@antonagestam antonagestam commented Feb 8, 2022

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
6 participants