Skip to content

Commit

Permalink
Support nested tuple unpacking in for loops
Browse files Browse the repository at this point in the history
Fixed issue where unpacking nested tuples in a for loop using would raise a
"couldn't apply loop context" error if the loop context was used. The regex
used to match the for loop expression now allows the list of loop variables
to contain parenthesized sub-tuples. Pull request courtesy Matt Trescott.

For example:
~~~
for (key1, val1), (key2, val2) in itertools.pairwise(dict.items()):
    ...
~~~

This is really just "kicking the can down the road" so to speak, because
it doesn't allow an infinite number of layers of tuples, but
it helps somewhat.

Closes: sqlalchemy#368
Pull-request: sqlalchemy#368
Pull-request-sha: 3f15a87

Change-Id: I52915acb8904daf7071d8c92e1de352f200131ec
  • Loading branch information
mtc-mlx authored and zzzeek committed Nov 15, 2022
1 parent 0c4e737 commit 2c0f1e7
Show file tree
Hide file tree
Showing 3 changed files with 26 additions and 2 deletions.
9 changes: 9 additions & 0 deletions doc/build/unreleased/368.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
.. change::
:tags: bug, codegen
:tickets: 368

Fixed issue where unpacking nested tuples in a for loop using would raise a
"couldn't apply loop context" error if the loop context was used. The regex
used to match the for loop expression now allows the list of loop variables
to contain parenthesized sub-tuples. Pull request courtesy Matt Trescott.

9 changes: 7 additions & 2 deletions mako/codegen.py
Original file line number Diff line number Diff line change
Expand Up @@ -1251,8 +1251,13 @@ def visitCallTag(self, node):


_FOR_LOOP = re.compile(
r"^for\s+((?:\(?)\s*[A-Za-z_][A-Za-z_0-9]*"
r"(?:\s*,\s*(?:[A-Za-z_][A-Za-z0-9_]*),??)*\s*(?:\)?))\s+in\s+(.*):"
r"^for\s+((?:\(?)\s*"
r"(?:\(?)\s*[A-Za-z_][A-Za-z_0-9]*"
r"(?:\s*,\s*(?:[A-Za-z_][A-Za-z_0-9]*),??)*\s*(?:\)?)"
r"(?:\s*,\s*(?:"
r"(?:\(?)\s*[A-Za-z_][A-Za-z_0-9]*"
r"(?:\s*,\s*(?:[A-Za-z_][A-Za-z_0-9]*),??)*\s*(?:\)?)"
r"),??)*\s*(?:\)?))\s+in\s+(.*):"
)


Expand Down
10 changes: 10 additions & 0 deletions test/test_loop.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,16 @@ def test__FOR_LOOP(self):
"x",
"[y+1 for y in [1, 2, 3]]",
),
(
"for ((key1, val1), (key2, val2)) in pairwise(dict.items()):",
"((key1, val1), (key2, val2))",
"pairwise(dict.items())",
),
(
"for (key1, val1), (key2, val2) in pairwise(dict.items()):",
"(key1, val1), (key2, val2)",
"pairwise(dict.items())",
),
):
match = _FOR_LOOP.match(statement)
assert match and match.groups() == (target_list, expression_list)
Expand Down

0 comments on commit 2c0f1e7

Please sign in to comment.