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

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

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

Comments

Projects
None yet
5 participants
@gvanrossum
Member

gvanrossum commented May 17, 2016

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

This comment has been minimized.

Show comment
Hide comment
@yaseppochi

yaseppochi May 17, 2016

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".

yaseppochi commented May 17, 2016

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

This comment has been minimized.

Show comment
Hide comment
@JukkaL

JukkaL May 17, 2016

Collaborator

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.

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

This comment has been minimized.

Show comment
Hide comment
@gvanrossum

gvanrossum May 17, 2016

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.

Member

gvanrossum commented May 17, 2016

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

This comment has been minimized.

Show comment
Hide comment
@rwbarton

rwbarton May 18, 2016

Contributor

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.

Contributor

rwbarton commented May 18, 2016

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

This comment has been minimized.

Show comment
Hide comment
@JukkaL

JukkaL May 18, 2016

Collaborator

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

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