[Python-checkins] bpo-44142: drop redundant parantheses when unparsing tuples as assignment targets (GH-26156)

isidentical webhook-mailer at python.org
Sun May 16 09:33:30 EDT 2021


https://github.com/python/cpython/commit/51cef8be8c77dff522bec6f95d6853031bf19038
commit: 51cef8be8c77dff522bec6f95d6853031bf19038
branch: main
author: Batuhan Taskaya <isidentical at gmail.com>
committer: isidentical <isidentical at gmail.com>
date: 2021-05-16T16:33:22+03:00
summary:

bpo-44142: drop redundant parantheses when unparsing tuples as assignment targets (GH-26156)

files:
A Misc/NEWS.d/next/Library/2021-05-16-02-24-23.bpo-44142.t-XU8k.rst
M Lib/ast.py
M Lib/test/test_ast.py
M Lib/test/test_unparse.py

diff --git a/Lib/ast.py b/Lib/ast.py
index 0aef172516b3fd..64487d2f0a60e5 100644
--- a/Lib/ast.py
+++ b/Lib/ast.py
@@ -640,7 +640,8 @@ class Param(expr_context):
 class _Precedence:
     """Precedence table that originated from python grammar."""
 
-    TUPLE = auto()
+    NAMED_EXPR = auto()      # <target> := <expr1>
+    TUPLE = auto()           # <expr1>, <expr2>
     YIELD = auto()           # 'yield', 'yield from'
     TEST = auto()            # 'if'-'else', 'lambda'
     OR = auto()              # 'or'
@@ -838,7 +839,7 @@ def visit_Expr(self, node):
         self.traverse(node.value)
 
     def visit_NamedExpr(self, node):
-        with self.require_parens(_Precedence.TUPLE, node):
+        with self.require_parens(_Precedence.NAMED_EXPR, node):
             self.set_precedence(_Precedence.ATOM, node.target, node.value)
             self.traverse(node.target)
             self.write(" := ")
@@ -859,6 +860,7 @@ def visit_ImportFrom(self, node):
     def visit_Assign(self, node):
         self.fill()
         for target in node.targets:
+            self.set_precedence(_Precedence.TUPLE, target)
             self.traverse(target)
             self.write(" = ")
         self.traverse(node.value)
@@ -1030,6 +1032,7 @@ def visit_AsyncFor(self, node):
 
     def _for_helper(self, fill, node):
         self.fill(fill)
+        self.set_precedence(_Precedence.TUPLE, node.target)
         self.traverse(node.target)
         self.write(" in ")
         self.traverse(node.iter)
@@ -1315,7 +1318,7 @@ def write_item(item):
             )
 
     def visit_Tuple(self, node):
-        with self.delimit("(", ")"):
+        with self.require_parens(_Precedence.TUPLE, node):
             self.items_view(self.traverse, node.elts)
 
     unop = {"Invert": "~", "Not": "not", "UAdd": "+", "USub": "-"}
diff --git a/Lib/test/test_ast.py b/Lib/test/test_ast.py
index 80d24e94040bcf..249e4bf6b3c6b8 100644
--- a/Lib/test/test_ast.py
+++ b/Lib/test/test_ast.py
@@ -702,7 +702,8 @@ def test_constant_as_name(self):
     def test_precedence_enum(self):
         class _Precedence(enum.IntEnum):
             """Precedence table that originated from python grammar."""
-            TUPLE = enum.auto()
+            NAMED_EXPR = enum.auto()      # <target> := <expr1>
+            TUPLE = enum.auto()           # <expr1>, <expr2>
             YIELD = enum.auto()           # 'yield', 'yield from'
             TEST = enum.auto()            # 'if'-'else', 'lambda'
             OR = enum.auto()              # 'or'
diff --git a/Lib/test/test_unparse.py b/Lib/test/test_unparse.py
index 4d3340e26ff02f..63151ec89d8551 100644
--- a/Lib/test/test_unparse.py
+++ b/Lib/test/test_unparse.py
@@ -541,6 +541,43 @@ def test_lambda_parameters(self):
         self.check_src_roundtrip("lambda x, y, /, z, q, *, u: None")
         self.check_src_roundtrip("lambda x, *y, **z: None")
 
+    def test_star_expr_assign_target(self):
+        for source_type, source in [
+            ("single assignment", "{target} = foo"),
+            ("multiple assignment", "{target} = {target} = bar"),
+            ("for loop", "for {target} in foo:\n    pass"),
+            ("async for loop", "async for {target} in foo:\n    pass")
+        ]:
+            for target in [
+                "a",
+                "a,",
+                "a, b",
+                "a, *b, c",
+                "a, (b, c), d",
+                "a, (b, c, d), *e",
+                "a, (b, *c, d), e",
+                "a, (b, *c, (d, e), f), g",
+                "[a]",
+                "[a, b]",
+                "[a, *b, c]",
+                "[a, [b, c], d]",
+                "[a, [b, c, d], *e]",
+                "[a, [b, *c, d], e]",
+                "[a, [b, *c, [d, e], f], g]",
+                "a, [b, c], d",
+                "[a, b, (c, d), (e, f)]",
+                "a, b, [*c], d, e"
+            ]:
+                with self.subTest(source_type=source_type, target=target):
+                    self.check_src_roundtrip(source.format(target=target))
+
+    def test_star_expr_assign_target_multiple(self):
+        self.check_src_roundtrip("a = b = c = d")
+        self.check_src_roundtrip("a, b = c, d = e, f = g")
+        self.check_src_roundtrip("[a, b] = [c, d] = [e, f] = g")
+        self.check_src_roundtrip("a, b = [c, d] = e, f = g")
+
+
 
 class DirectoryTestCase(ASTTestCase):
     """Test roundtrip behaviour on all files in Lib and Lib/test."""
diff --git a/Misc/NEWS.d/next/Library/2021-05-16-02-24-23.bpo-44142.t-XU8k.rst b/Misc/NEWS.d/next/Library/2021-05-16-02-24-23.bpo-44142.t-XU8k.rst
new file mode 100644
index 00000000000000..96fdd7c6566b20
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2021-05-16-02-24-23.bpo-44142.t-XU8k.rst
@@ -0,0 +1,2 @@
+:func:`ast.unparse` will now drop the redundant parentheses when tuples used
+as assignment targets (e.g in for loops).



More information about the Python-checkins mailing list