Skip to content

Commit d7e9dfe

Browse files
committed
correctly handle iterators in tuple assignments; fixes #15
1 parent a1ad5a4 commit d7e9dfe

File tree

2 files changed

+29
-12
lines changed

2 files changed

+29
-12
lines changed

custom_components/pyscript/eval.py

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -602,17 +602,19 @@ async def recurse_assign(self, lhs, val):
602602
"""Recursive assignment."""
603603
if isinstance(lhs, ast.Tuple):
604604
try:
605-
val_len = len(val)
606-
except TypeError:
607-
raise TypeError("cannot unpack non-iterable object")
608-
if len(lhs.elts) < val_len:
609-
raise ValueError(
610-
f"too many values to unpack (expected {len(lhs.elts)})"
611-
)
612-
if len(lhs.elts) > val_len:
613-
raise ValueError(f"too few values to unpack (expected {len(lhs.elts)})")
614-
for lhs_elt, val_elt in zip(lhs.elts, val):
605+
val_iter = val.__iter__()
606+
except AttributeError:
607+
raise TypeError("cannot unpack non-iterable object")
608+
sentinel = object()
609+
for lhs_elt in lhs.elts:
610+
val_elt = next(val_iter, sentinel)
611+
if val_elt is sentinel:
612+
raise TypeError(
613+
f"too few values to unpack (expected {len(lhs.elts)})"
614+
)
615615
await self.recurse_assign(lhs_elt, val_elt)
616+
if next(val_iter, sentinel) is not sentinel:
617+
raise TypeError(f"too many values to unpack (expected {len(lhs.elts)})")
616618
elif isinstance(lhs, ast.Subscript):
617619
var = await self.aeval(lhs.value)
618620
if isinstance(lhs.slice, ast.Index):

tests/custom_components/pyscript/test_unit_eval.py

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@
5555
["z = [1,2,3]; [z[1], z[-1]]", [2, 3]],
5656
["'{1} {0}'.format('one', 'two')", "two one"],
5757
["'%d, %d' % (23, 45)", "23, 45"],
58+
["x = [[1,2,3]]; sum(*x)", 6],
5859
["args = [1, 5, 10]; {6, *args, 15}", {1, 5, 6, 10, 15}],
5960
["args = [1, 5, 10]; [6, *args, 15]", [6, 1, 5, 10, 15]],
6061
["kw = {'x': 1, 'y': 5}; {**kw}", {"x": 1, "y": 5}],
@@ -145,6 +146,12 @@
145146
"z = [1,2,3]; ((x, y), (z[2], t)) = ((1, 2), (20, 4)); [x, y, z, t]",
146147
[1, 2, [1, 2, 20], 4],
147148
],
149+
["a, b, c = [1,2,3]; [a, b, c]", [1, 2, 3]],
150+
["a, b, c = iter([1,2,3]); [a, b, c]", [1, 2, 3]],
151+
[
152+
"tuples = [(1, 2), (3, 4), (5, 6)]; a, b = zip(*tuples); [a, b]",
153+
[(1, 3, 5), (2, 4, 6)],
154+
],
148155
["Foo = type('Foo', (), {'x': 100}); Foo.x = 10; Foo.x", 10],
149156
["Foo = type('Foo', (), {'x': 100}); Foo.x += 10; Foo.x", 110],
150157
["Foo = [type('Foo', (), {'x': 100})]; Foo[0].x = 10; Foo[0].x", 10],
@@ -664,11 +671,19 @@ def test_eval(hass):
664671
["xx", "Exception in test line 1 column 0: name 'xx' is not defined"],
665672
[
666673
"(x, y) = (1, 2, 4)",
667-
"Exception in test line 1 column 16: too many values to unpack (expected 2)",
674+
"Exception in test line 1 column 4: too many values to unpack (expected 2)",
675+
],
676+
[
677+
"(x, y) = iter([1, 2, 4])",
678+
"Exception in test line 1 column 4: too many values to unpack (expected 2)",
668679
],
669680
[
670681
"(x, y, z) = (1, 2)",
671-
"Exception in test line 1 column 16: too few values to unpack (expected 3)",
682+
"Exception in test line 1 column 4: too few values to unpack (expected 3)",
683+
],
684+
[
685+
"(x, y, z) = iter([1, 2])",
686+
"Exception in test line 1 column 4: too few values to unpack (expected 3)",
672687
],
673688
[
674689
"(x, y) = 1",

0 commit comments

Comments
 (0)