Skip to content
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

Unpacking starred expressions in tuples #7779

Closed
goodmami opened this issue Oct 23, 2019 · 7 comments · Fixed by #8827
Closed

Unpacking starred expressions in tuples #7779

goodmami opened this issue Oct 23, 2019 · 7 comments · Fixed by #8827
Labels

Comments

@goodmami
Copy link
Contributor

(migrated from a comment in #1178 at @ethanhs's request)

There seems to an issue with unpacking things when they are part of a tuple on the right side of assignment. #1178 is related, but specifically deals with variable-length tuples (and using len() to distinguish them). The current issue occurs even for fixed-length and type-annotated tuples.

# file: ex.py
from typing import Tuple
points = (1, 2)  # type: Tuple[int, int]
x, y, z = *points, 0

This results in incorrect inference about the tuple size (but Python does not complain, only mypy):

$ mypy ex.py 
ex.py:4: error: Need more than 2 values to unpack (3 expected)
Found 1 error in 1 file (checked 1 source file)

A workaround is to use cast(), as @JukkaL suggested:

x, y, z = cast(Tuple[int, int, int], (*points, 0))

And here's my versions of Python and mypy:

$ mypy --version
mypy 0.740
$ python --version
Python 3.7.3
@msullivan
Copy link
Collaborator

It looks like the issue is in check_assignment_to_multiple_lvalues, where it has a case for a tuple RHS but doesn't take into account star exprs.

This is a decent starter issue, maybe, if someone wants it.

@goodmami
Copy link
Contributor Author

@msullivan I'd be happy to give this a shot

@goodmami
Copy link
Contributor Author

goodmami commented Oct 26, 2019

Update: I added a test to test-data/unit/check-tuples.test:

[case testTupleWithStarExpr5]
a = (1, 2)
b, c = (*a, 3)  # E: Too many values to unpack (2 expected, 3 provided)
b, c, d = (*a, 3)
b, c, d, e = (*a, 3)  # E: Need more than 3 values to unpack (2 expected)
[builtins fixtures/tuple.pyi]

The test fails as expected. But now I'm stuck in check_assignment_to_multiple_lvalues trying to unpack the starred expression to get its inner types. I tried flatten(x) and x.expr.node.type.items but these aren't quite right. Are there developer docs for working with these things or can I get some hints on how to proceed? (edit: I found the developer docs, at least)

@goodmami
Copy link
Contributor Author

goodmami commented Oct 28, 2019

Ok, I'm still learning about mypy internals but here's where I'm at: I can get an accurate type signature for the right hand side of assignment (even for silly examples with nested starred-expressions like *(*a, 3), 4) with self.expr_checker.accept(rvalue) (in TypeChecker.check_assignment_to_multiple_lvalues()), and this passes the check for the appropriate number of items on the left and right side, but then it fails when it tries to call self.check_assignment() on each paired left and right value. I think this is because the function expects an AST expression and I'm giving it a resolved type. Also even if I could give the function the original expressions I don't think they would help because of examples like x, *y = *a, b (which crashes mypy, btw), where the assignment crosses tree branches (y gets a[1:] + [b]).

I'm not sure if there's a more straightforward way of doing this. If it's obvious to anyone else, any hints as to what I'm missing would be appreciated.

@goodmami
Copy link
Contributor Author

I'm not currently working on this anymore. Just mentioning this in case someone else wants to take it on.

@Holmes7
Copy link

Holmes7 commented Feb 26, 2020

I would like to work on this issue. Any pointers to keep in mind?

@JukkaL
Copy link
Collaborator

JukkaL commented Feb 28, 2020

I think this is because the function expects an AST expression and I'm giving it a resolved type.

TempNode may help in cases like this. It can be used to create a dummy AST node with some type.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants