|
33 | 33 |
|
34 | 34 |
|
35 | 35 | if TYPE_CHECKING:
|
| 36 | + from typing import NoReturn |
36 | 37 | from typing import Type
|
37 | 38 | from typing_extensions import Final
|
38 | 39 |
|
@@ -401,3 +402,38 @@ def __get__(self, instance, owner=None): # noqa: F811
|
401 | 402 | from collections import OrderedDict
|
402 | 403 |
|
403 | 404 | order_preserving_dict = OrderedDict
|
| 405 | + |
| 406 | + |
| 407 | +# Perform exhaustiveness checking. |
| 408 | +# |
| 409 | +# Consider this example: |
| 410 | +# |
| 411 | +# MyUnion = Union[int, str] |
| 412 | +# |
| 413 | +# def handle(x: MyUnion) -> int { |
| 414 | +# if isinstance(x, int): |
| 415 | +# return 1 |
| 416 | +# elif isinstance(x, str): |
| 417 | +# return 2 |
| 418 | +# else: |
| 419 | +# raise Exception('unreachable') |
| 420 | +# |
| 421 | +# Now suppose we add a new variant: |
| 422 | +# |
| 423 | +# MyUnion = Union[int, str, bytes] |
| 424 | +# |
| 425 | +# After doing this, we must remember ourselves to go and update the handle |
| 426 | +# function to handle the new variant. |
| 427 | +# |
| 428 | +# With `assert_never` we can do better: |
| 429 | +# |
| 430 | +# // throw new Error('unreachable'); |
| 431 | +# return assert_never(x) |
| 432 | +# |
| 433 | +# Now, if we forget to handle the new variant, the type-checker will emit a |
| 434 | +# compile-time error, instead of the runtime error we would have gotten |
| 435 | +# previously. |
| 436 | +# |
| 437 | +# This also work for Enums (if you use `is` to compare) and Literals. |
| 438 | +def assert_never(value: "NoReturn") -> "NoReturn": |
| 439 | + assert False, "Unhandled value: {} ({})".format(value, type(value).__name__) |
0 commit comments