-
-
Notifications
You must be signed in to change notification settings - Fork 2.9k
Unions break with isinstance()
#1135
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
Comments
This is quite possibly one of the most bizarre error messages I've ever seen... |
Passes on py3 except for a mypy bug (python/mypy#1135). Still some failures on py2.
Hm, looks like the way unicode was hacked into --py2 mode has a problem.
(Replacing bytes with str makes no difference, so the problem must be
caused by unicode.)
FWIW, not trying to discredit your bug report, but why are you using
Union[unicode, bytes] here instead of AnyStr?
|
The evil seems to be due to the mapping (in semanal.py, in
TYPE_PROMOTIONS_PYTHON2) from 'builtins.str' to 'builtins.unicode'. If I
comment out that line and fix a bunch of errors in typeshed, the errors go
away. (This also explains that the corresponding code doesn't have a
problem PY3 mode.)
This doesn't really explain the root cause or provide a fix.
However, it led me to a repro not depending on --py2 or unicode:
import typing
def foo(value):
# type: (typing.Union[int, float]) -> None
if isinstance(value, float):
return
if isinstance(value, int):
return
type(value)
This proves that the root cause has something to do with type promotions of
this kind. More particular, they seem to interfere with the special-casing
of control flow involving isinstance() checks that limit the type of a
variable to one of the union branches (as in these examples).
And although there's special-casing of type(), that seems to be a secondary
error; if I replace type(value) with foo(value) I get almost the same error:
ben2.py:8: error: Argument 1 to "type" has incompatible type "Union[object,
object, object, object]"; expected "object"
which suggests that due to the flow-control hacking for isinstance() the
type of value on the last line is a monstrosity.
|
As a This also shows up in the typeshed stubs for the 2.7
So I guess this raises a kind of philosophical question about whether the type checker should try to allow everything that would actually work in python 2, or if it should be a "strict mode" that forces code like the above to be more explicit about its unicode handling. |
AnyStr is meant to be public -- it's documented in PEP 484. I have to think On Sat, Jan 16, 2016 at 11:01 PM, Ben Darnell [email protected]
--Guido van Rossum (python.org/~guido) |
Obviously mypy is not type checking the original example correctly. I'll look into it. The intention is that |
In python 2, |
Heh, so maybe we should remove the str->unicode entry from the type On Sun, Jan 17, 2016 at 10:01 AM, Ben Darnell [email protected]
--Guido van Rossum (python.org/~guido) |
I wouldn't remove the There are basically at least four ways we can approach this:
These also affect how stubs should be written:
Note that mypy currently assumes approach 1 and I don't know how well the other approaches would work in practice. EDIT: "blowing up" -> "sometimes blowing up" |
Here's a slightly simplified Python 3 fragment that reproduces the problem:
Output:
This seems to be an interaction between |
Actually, this is not related to special built-in type subtyping rules. This also fails:
Output:
We should simplify union types where one type is a subtype of another type. It seems to be that we assume that union types are simplified somewhere in the code and if this is not the case, things break. |
This was pretty bizarre through some complex interactions and fun to track down. Here's a synopsis:
We should still add some defensive assertions to make problems like this easier to figure out. |
Regarding the "four ways" comment above (what's the best place to continue this discussion? a new issue?): Tornado uses a different (fifth?) way that uses more types, but I have found them all to be necessary in writing code that spans python 2 and 3. The types (and/or type conversion functions; it's a little fuzzy in the pre-type-annotation world) are:
Most functions try to be permissive in their inputs and accept I'm going to be annotating most of my arguments with |
I created a new issue #1141 for str/unicode; let's move the discussion there. |
Mypy incorrectly reports two errors in this (python 2) snippet.
If lines 5 and 6 are removed, the errors disappear. If line 7 is replaced with
if True:
, the error on line 8 remains. Replacingunicode
withstr
and running mypy in py3 mode also makes the errors disappear.The text was updated successfully, but these errors were encountered: