]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
bpo-44142: drop redundant parantheses when unparsing tuples as assignment targets...
authorBatuhan Taskaya <isidentical@gmail.com>
Sun, 16 May 2021 13:33:22 +0000 (16:33 +0300)
committerGitHub <noreply@github.com>
Sun, 16 May 2021 13:33:22 +0000 (16:33 +0300)
Lib/ast.py
Lib/test/test_ast.py
Lib/test/test_unparse.py
Misc/NEWS.d/next/Library/2021-05-16-02-24-23.bpo-44142.t-XU8k.rst [new file with mode: 0644]

index 0aef172516b3fda9177396c00aa672d42ed85be0..64487d2f0a60e5c6282629c75459712c6c9a5b89 100644 (file)
@@ -640,7 +640,8 @@ _INFSTR = "1e" + repr(sys.float_info.max_10_exp + 1)
 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 @@ class _Unparser(NodeVisitor):
         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 @@ class _Unparser(NodeVisitor):
     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 @@ class _Unparser(NodeVisitor):
 
     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 @@ class _Unparser(NodeVisitor):
             )
 
     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": "-"}
index 80d24e94040bcfc13ab12bc9fd7efe506592fa20..249e4bf6b3c6b8e72d0d418a3b63efcda43bf307 100644 (file)
@@ -702,7 +702,8 @@ class AST_Tests(unittest.TestCase):
     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'
index 4d3340e26ff02fb308dee0e114c07f9f74946835..63151ec89d8551b7e273f44c2ff9c96dd32287cf 100644 (file)
@@ -541,6 +541,43 @@ class CosmeticTestCase(ASTTestCase):
         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 (file)
index 0000000..96fdd7c
--- /dev/null
@@ -0,0 +1,2 @@
+:func:`ast.unparse` will now drop the redundant parentheses when tuples used
+as assignment targets (e.g in for loops).