-
-
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
FR: Type narrowing for x is C #7642
Comments
I'm guessing I'd have to modify |
Did you mean to request this specifically for |
Using A more representative use case would be as follows:
In the current version of mypy the two I could make it work by changing my project around to use it like this:
However, I would prefer the readability of my first example, if at all possible. |
In your first example, it would be incorrect in general for mypy to infer |
Hm, this is because once I use a class to define a type, I introduce the possibility of inheritance, yes? But I have no use for inheritance. Can you tell me how to change the example so there is no risk of inheritance? |
I can't do it like this either: from typing import Type, Union
class MissingType:
pass
Missing = MissingType()
def my_func(a: Union[MissingType, int]) -> None:
if a is Missing:
reveal_type(a) # N: Revealed type is 'Type[foo2.MissingType]'
else:
reveal_type(a) # N: Revealed type is 'builtins.int' Since mypy has no way of knowing that Missing is (or at least should be) the only possible instance of MissingType. I guess I'm trying to do something like Haskell's Maybe type: data Maybe a = Just a | Nothing In this case, |
You can do this if you just use |
I'm aware, however, None is a valid value separate from |
So tell me if I'm wrong. You're trying to introduce a singleton value other than None, and you want the type checker to understand code that excludes the singleton value. I think this is a reasonable request. There are two aspects to the puzzle: how to make testing for the singleton value look intuitive, and how to make the type checker understand it. When we have solved both we can recommend a way to define singletion values and how to test for them. Traditionally this would be done like this: nothing = object()
def foo(arg=nothing):
if arg is nothing:
<default case>
else:
<regular case> How can we do it type-safely? Apparently there isn't an easy way to spell this without Maybe we can may mypy realize that enums (if they define any values) cannot be subclassed and have unique values, and then the "nothing" marker could be a member of a one-element enum:
|
@gvanrossum The enum solution already works in mypy (except aliasing enum members will likely not work, unless you make variable a literal type or final). Taking into account this, should we still keep this open, or is it a satisfactory solution? |
Maybe it might be sufficient to just add a check for this inside https://github.com/python/mypy/blob/master/mypy/checker.py#L4720? Specifically, we could perhaps modify that check so that it also returns true if we have some type of the form |
What about also special casing Making Whatever we decide to implement, it would be good to document this. The supported way to do this is probably not obvious to all users, since it looks like the |
In my testing the enum solution does not work with `is`; you have to use
`isinstance()` which is pretty unsatisfactory. So special-casing `is` for a
single-value enum (or a Literal[] containing a single value) might help.
|
Both ideas for special-casing makes sense. Now we need to find a volunteer to implement them :-) |
Hm, the example from @gvanrossum with enums DOES work if the
Adding a second type to the enum values in the one value being discarded, leaving only literals for the remaining enum values. I'm not sure this is actually documented, though. It's tested in Extending |
D'oh, I forgot you have to add The behavior with Enum members and Can we close this issue? |
Initially I thought so, but I think ideas @Michael0x2a and @JukkaL proposed make sense:
|
I can confirm the Enum trick works for my case. I would also like to support @ilevkivskyi suggestions; option two feels a bit more natural than this one weird enum trick; updating the documentation would have let me find the enum trick sooner. At the moment, the documentation seems to hint to me that using Though I'm not sure about the suggestion regarding |
Since the enum has only one possible value, there is nothing else that can be assigned to it (that still matches the type). |
This is a feature request.
Example unit test:
For a project I'm working on, it would be help readability if I could write code like the above. However, mypy does not perform type narrowing in this case, so that results in a lot of type warnings.
Note: This is different from
type(x) is C
. In this case, x is the type instance itself, so no subclasses are involved.The text was updated successfully, but these errors were encountered: