summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatt Trescott <mtc@melexis.com>2022-11-10 10:30:21 -0500
committerMike Bayer <mike_mp@zzzcomputing.com>2022-11-15 09:07:35 -0500
commit2c0f1e7df0fe7a9b0687143a4f442994081430c6 (patch)
tree14651d18b345834467c27b20e73fda65a397600d
parent0c4e737ff7d2a586c42f848441fef1386f2900e0 (diff)
downloadmako-2c0f1e7df0fe7a9b0687143a4f442994081430c6.tar.gz
Support nested tuple unpacking in for loops
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: #368 Pull-request: https://github.com/sqlalchemy/mako/pull/368 Pull-request-sha: 3f15a87266a36306826d460cddc7699dd62a9c43 Change-Id: I52915acb8904daf7071d8c92e1de352f200131ec
-rw-r--r--doc/build/unreleased/368.rst9
-rw-r--r--mako/codegen.py9
-rw-r--r--test/test_loop.py10
3 files changed, 26 insertions, 2 deletions
diff --git a/doc/build/unreleased/368.rst b/doc/build/unreleased/368.rst
new file mode 100644
index 0000000..73d4bcb
--- /dev/null
+++ b/doc/build/unreleased/368.rst
@@ -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.
+
diff --git a/mako/codegen.py b/mako/codegen.py
index a9dbcb6..d1d2c20 100644
--- a/mako/codegen.py
+++ b/mako/codegen.py
@@ -1251,8 +1251,13 @@ class _Identifiers:
_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+(.*):"
)
diff --git a/test/test_loop.py b/test/test_loop.py
index d048ed0..2c11000 100644
--- a/test/test_loop.py
+++ b/test/test_loop.py
@@ -31,6 +31,16 @@ class TestLoop(unittest.TestCase):
"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)