Unconstrained type variable combined with isinstance() doesn't seem to work #1539

Closed
gvanrossum opened this Issue May 17, 2016 · 5 comments

Projects

None yet

5 participants

@gvanrossum
Member

Not sure this is a bug or not...

from typing import TypeVar

S = TypeVar('S')

def parenthesize(s: S) -> S:
    if isinstance(s, str):
        return '(' + s + ')'
    elif isinstance(s, bytes):
        return b'(' + s + b')'
    else:
        raise TypeError("That's not a string, dude! It's a %s" % type(s))

This gets errors on both return lines:

demo.py: note: In function "parenthesize":
demo.py:7: error: Incompatible return value type: expected S`-1, got builtins.str
demo.py:9: error: Incompatible return value type: expected S`-1, got builtins.bytes

Why? The isinstance() checks look like they should provide sufficient guards.

@yaseppochi

I'm guessing that s might be of a non-str, non-bytes type, and mypy doesn't recognize "else: raise" as a type guard. I'm currently in day-job avoidance, so I'd better not go find out by replacing the "raise" with "return s".

@JukkaL
Collaborator
JukkaL commented May 17, 2016

The reason the example doesn't work is that after the isinstance() the type of s is str (or bytes), but nothing else changes -- in particular, the return type is still S. str is not a subtype of S, so mypy rejects the return statement.

To make the example work, mypy could perhaps somehow keep track of the fact that S must be a supertype of str after the first isinstance() check, and use this information when checking the return statement.

@gvanrossum
Member

Oh dang. I totally missed that the errors were about the return type, not about the + operators. Oh well. Since I blogged about this and linked to this issue from the blog, you can expect some more drive-by comments.

@rwbarton
Collaborator

Actually this particular program really is invalid because S might be a subtype of str; then isinstance(s, str) will be true but '(' + s + ')' is still only a str and not an S.

If you change both return statements to return s, though, the program is valid but mypy still rejects it, because it doesn't know how to use both pieces of information simultaneously: that s is of type str and also of type S.

@JukkaL
Collaborator
JukkaL commented May 18, 2016

@rwbarton True, I got it wrong. In any case, this is a pretty subtle issue and doesn't look like a high-priority one.

@ddfisher ddfisher added this to the Questions milestone May 19, 2016
@gvanrossum gvanrossum closed this Jan 6, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment