-
Notifications
You must be signed in to change notification settings - Fork 1.2k
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
[red-knot] Add the special logic for int/float/complex in annotations #14932
Comments
Wow interesting. Should we add an optional rule that warns about such "incompatible" default values? I don't think I'd want that behavior 😆 |
It would conflict with https://docs.astral.sh/ruff/rules/redundant-numeric-union/ ;) |
I suppose we could make that rule configurable so that you can "reverse" the behaviour and enforce the opposite... |
Really? So x: float = 0 is not? This seems inconsistent to me. Neither mypy nor pyright have this behavior. https://mypy.readthedocs.io/en/stable/duck_type_compatibility.html#duck-type-compatibility. Does the wording in the spec maybe predate variable annotations or is this really what the spec intends? Why? |
Oh, this seems relevant 😄: python/typing#1746 |
The spec as a whole is very new and long post-dates variable annotations, but this special case does indeed long predate variable annotations (it was introduced by PEP 484). You're correct that mypy and pyright do sometimes extend this behaviour to other contexts. It can be pretty inconsistent and surprising when they do, however! For example: x: float = 0
reveal_type(x) # mypy: float
if isinstance(x, int):
reveal_type(x) # mypy: int (not Never? Or <subclass of int and float>? Huh?)
else:
reveal_type(x) # revealed: float I.e., I believe mypy when mypy sees All of this is underspecified and we can defer a lot of it. But the behaviour for parameter annotations specifically is well-specified and important -- and our lack of support for it is causing false positives now! |
The odd behavior you point out here is inherent to the special case, and the way mypy implements it; it's not related to applying the special case to variable annotations. Exactly the same behavior appears with a function parameter annotation, too: https://mypy-play.net/?mypy=latest&python=3.12&gist=d1d1c0ed731ca0afe425f427fbb7e302 I think the only reason the spec implies this is only for parameter annotations is because the text predates variable annotations; I don't believe there is any good reason to limit it to parameter annotations, nor does any existing type checker do that. So I don't believe we should do so either.
Yes, I think this is right; and pyright does this too. I think this is the best way to implement this special case, as compared to the alternative of actually treating The strangeness you observe in the above example really comes entirely from the fact that mypy tries to "hide" this implicit My feeling is that we should treat a It's possible this will get us in trouble with overly-aggressive use of (Also of course we must treat an annotation of |
Thanks @carljm. That all sounds reasonable to me, except for the fact that it does mean there's no way to express in a stub file, for example, that an instance attribute really will be exactly a |
And from the perspective of users, I would encourage them to only make use of the special case in parameter annotations. The intuition that led to this special case was that "nearly all functions that accept floats will also work fine with ints in practice" -- for all the flaws of the special case (and there are many! if only Python had a better runtime numeric tower so we didn't have to hack around it in the type system) it does make parameter annotations a lot less fiddly in many situations. But I don't think there's nearly the same benefits for users outside of the context of parameter annotations. This isn't an argument against what you're saying -- I agree consistent behaviour is probably more important here. |
Yeah, this is the main downside of the special case. If we had intersections you could say |
Given this Python function:
red-knot currently issues this complaint:
This is incorrect. Although
Literal[42]
is not a subtype offloat
, the typing spec carves out a special case for numeric types when used specifically in function parameter annotations:We need to implement this special case to avoid false-positive errors like the one above. Note that the special case only applies in function parameter annotations, not in any other context. Note also that all subtypes of
int
should also be considered assignable tofloat
(and, transitively,complex
) in this context:Literal[42]
,bool
andLiteral[True]
are also therefore assignable tofloat
andcomplex
in the context of parameter annotations.The text was updated successfully, but these errors were encountered: