From c102a148256b00b7d48c51a1a97df19042e603de Mon Sep 17 00:00:00 2001 From: Batuhan Taskaya Date: Mon, 18 May 2020 23:48:49 +0300 Subject: [PATCH] bpo-38870: Don't omit parenthesis when unparsing a slice in ast.unparse When unparsing a non-empty tuple, the parentheses can be safely omitted if there aren't any elements that explicitly require them (such as starred expressions). --- Lib/ast.py | 12 +++++++++++- Lib/test/test_unparse.py | 10 +++++++++- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/Lib/ast.py b/Lib/ast.py index 2edb7171e96..52e51b48587 100644 --- a/Lib/ast.py +++ b/Lib/ast.py @@ -1356,10 +1356,20 @@ def visit_Call(self, node): self.traverse(e) def visit_Subscript(self, node): + def is_simple_tuple(slice_value): + # when unparsing a non-empty tuple, the parantheses can be safely + # omitted if there aren't any elements that explicitly requires + # parantheses (such as starred expressions). + return ( + isinstance(slice_value, Tuple) + and slice_value.elts + and not any(isinstance(elt, Starred) for elt in slice_value.elts) + ) + self.set_precedence(_Precedence.ATOM, node.value) self.traverse(node.value) with self.delimit("[", "]"): - if isinstance(node.slice, Tuple) and node.slice.elts: + if is_simple_tuple(node.slice): self.items_view(self.traverse, node.slice.elts) else: self.traverse(node.slice) diff --git a/Lib/test/test_unparse.py b/Lib/test/test_unparse.py index 6d828721b77..bb725ced64d 100644 --- a/Lib/test/test_unparse.py +++ b/Lib/test/test_unparse.py @@ -279,10 +279,13 @@ def test_dict_unpacking_in_dict(self): self.check_ast_roundtrip(r"""{**{'y': 2}, 'x': 1}""") self.check_ast_roundtrip(r"""{**{'y': 2}, **{'x': 1}}""") - def test_ext_slices(self): + def test_slices(self): self.check_ast_roundtrip("a[i]") self.check_ast_roundtrip("a[i,]") self.check_ast_roundtrip("a[i, j]") + self.check_ast_roundtrip("a[(*a,)]") + self.check_ast_roundtrip("a[(a:=b)]") + self.check_ast_roundtrip("a[(a:=b,c)]") self.check_ast_roundtrip("a[()]") self.check_ast_roundtrip("a[i:j]") self.check_ast_roundtrip("a[:j]") @@ -470,6 +473,11 @@ def test_unary_op_factor(self): for prefix in ("not",): self.check_src_roundtrip(f"{prefix} 1") + def test_slices(self): + self.check_src_roundtrip("a[1]") + self.check_src_roundtrip("a[1, 2]") + self.check_src_roundtrip("a[(1, *a)]") + class DirectoryTestCase(ASTTestCase): """Test roundtrip behaviour on all files in Lib and Lib/test."""