-
-
Notifications
You must be signed in to change notification settings - Fork 2.8k
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
Preferred idiom for exhaustiveness checking of unions #5818
Comments
Typescript also has a |
Isn't
|
This is a clever hack, and I would never have come up with that (probably because the use case is not one I commonly encounter). It makes sense to legitimize some form of this and document it. |
Hmm, at least according to the docs, it seems like Typescript's This difference might actually make this pattern unsafe in a few cases. For example:
In this case, since Not sure how big of an issue this is though in practice -- I figured I ought to just bring it up since it seems like a useful caveat to mention if we do document this trick. (Or I guess we could make NoReturn and Any interact in the same way they do in Typescript -- not sure how easy or hard that would be though.) |
I would also point out this would be inconsistent with PEP 484 which states that
Also, it might be nice to warn about using |
FWIW, after applying the following change, to which I reached with some printf debugging, mypy's test suite still passes, and the diff --git a/mypy/subtypes.py b/mypy/subtypes.py
index d06ad40f..c4a62a08 100644
--- a/mypy/subtypes.py
+++ b/mypy/subtypes.py
@@ -162,7 +162,7 @@ class SubtypeVisitor(TypeVisitor[bool]):
return True
def visit_any(self, left: AnyType) -> bool:
- return True
+ return not isinstance(self.right, UninhabitedType)
def visit_none_type(self, left: NoneTyp) -> bool:
if experiments.STRICT_OPTIONAL: |
The value of the argument of from typing import NoReturn
import enum
class Impossible(enum.Enum):
pass
def assert_never(x: Impossible) -> NoReturn:
assert False, "Unhandled type: {}".format(type(x).__name__) |
In that case you don't even have to inherit from Enum. You can just refrain
from creating instances. :-)
|
I would actually propose to remove this restriction from the PEP (if it is still OK), and make Regarding the subtyping between |
Wouldn't it make sense to introduce an alias for |
The name is a bit unusual indeed, but typical alternatives |
Personally, I find Typescript's |
I also like the name |
I my opinion I think that subtyping between |
This is not going to happen, it's too late. There are around 30K files in GitHub that use |
Is this really an argument? I think it is always better to consider such edge cases in the context of the whole picture, otherwise it may be inconsistent. For example joins and meets should behave consistently w.r.t. to subtyping. |
Sure, but I'm not seeing how #3194 is directly relevant here. #3194 proposes that we change the type system in certain ways, which may affect how Or do you believe that the current type system is inconsistent, and any additional changes to the type system could make it harder to make it consistent in the future? If so, I'd like to see more examples of what is currently wrong. |
We could perhaps rename |
This is the main question. We can of course do this ("two step" deprecation), but the question is whether Another question to consider is how to repr this type. Currently it is |
Summary: Ran into this when refactoring `PartitionSetDefinition`. This idiom appears in https://hakibenita.com/python-mypy-exhaustive-checking and python/mypy#5818 - this is a nice to ensure exhaustion when doing conditionals on enums. Test Plan: N/A Reviewers: dgibson, cdecarolis, alangenfeld Reviewed By: dgibson Differential Revision: https://dagster.phacility.com/D7642
|
Correct! It's also documented in https://typing.readthedocs.io/en/latest/source/unreachable.html |
A question...
I have some union, e.g.
and I have a function which takes the union and matches on it:
Now suppose that the union gets added a new member:
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):and use it as follows:
Now mypy warns:
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.
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?
Python 3.5.5, mypy 0.630.
no_implicit_optional, check_untyped_defs, warn_unused_ignores
.The text was updated successfully, but these errors were encountered: