From 5af5cfdd75c4247620f9e592d86aa290dd180f4b Mon Sep 17 00:00:00 2001 From: isidentical Date: Sun, 15 Dec 2019 14:00:47 +0300 Subject: [PATCH 1/5] bpo-38870: refactor delimiting with context managers --- Lib/ast.py | 292 +++++++++--------- .../2019-12-15-14-07-16.bpo-38870.8D28DB.rst | 1 + 2 files changed, 146 insertions(+), 147 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2019-12-15-14-07-16.bpo-38870.8D28DB.rst diff --git a/Lib/ast.py b/Lib/ast.py index 77eb24971ed24cb..a2b8815c79f3da2 100644 --- a/Lib/ast.py +++ b/Lib/ast.py @@ -613,6 +613,30 @@ def __exit__(self, exc_type, exc_value, traceback): def block(self): return self._Block(self) + class _NoDelimit: + def __enter__(self): pass + def __exit__(self, *args): pass + + class _Delimit: + """A context manager for preparing the source for expressions. It adds + start of the delimiter and enters, after exit it adds delimiter end.""" + def __init__(self, unparser, delimiter): + self.unparser = unparser + self.delimiter = delimiter + def __enter__(self): + self.unparser.write(self.delimiter[0]) + def __exit__(self, exc_type, exc_value, traceback): + self.unparser.write(self.delimiter[-1]) + + def delimit_if(self, condition, delimiter = "()"): + if condition: + return self._Delimit(self, delimiter) + else: + return self._NoDelimit() + + def delimit(self, delimiter = "()"): + return self._Delimit(self, delimiter) + def traverse(self, node): if isinstance(node, list): for item in node: @@ -636,11 +660,10 @@ def visit_Expr(self, node): self.traverse(node.value) def visit_NamedExpr(self, node): - self.write("(") - self.traverse(node.target) - self.write(" := ") - self.traverse(node.value) - self.write(")") + with self.delimit(): + self.traverse(node.target) + self.write(" := ") + self.traverse(node.value) def visit_Import(self, node): self.fill("import ") @@ -669,11 +692,8 @@ def visit_AugAssign(self, node): def visit_AnnAssign(self, node): self.fill() - if not node.simple and isinstance(node.target, Name): - self.write("(") - self.traverse(node.target) - if not node.simple and isinstance(node.target, Name): - self.write(")") + with self.delimit_if(not node.simple and isinstance(node.target, Name)): + self.traverse(node.target) self.write(": ") self.traverse(node.annotation) if node.value: @@ -715,28 +735,25 @@ def visit_Nonlocal(self, node): self.interleave(lambda: self.write(", "), self.write, node.names) def visit_Await(self, node): - self.write("(") - self.write("await") - if node.value: - self.write(" ") - self.traverse(node.value) - self.write(")") + with self.delimit(): + self.write("await") + if node.value: + self.write(" ") + self.traverse(node.value) def visit_Yield(self, node): - self.write("(") - self.write("yield") - if node.value: - self.write(" ") - self.traverse(node.value) - self.write(")") + with self.delimit(): + self.write("yield") + if node.value: + self.write(" ") + self.traverse(node.value) def visit_YieldFrom(self, node): - self.write("(") - self.write("yield from") - if node.value: - self.write(" ") - self.traverse(node.value) - self.write(")") + with self.delimit(): + self.write("yield from") + if node.value: + self.write(" ") + self.traverse(node.value) def visit_Raise(self, node): self.fill("raise") @@ -782,21 +799,20 @@ def visit_ClassDef(self, node): self.fill("@") self.traverse(deco) self.fill("class " + node.name) - self.write("(") - comma = False - for e in node.bases: - if comma: - self.write(", ") - else: - comma = True - self.traverse(e) - for e in node.keywords: - if comma: - self.write(", ") - else: - comma = True - self.traverse(e) - self.write(")") + with self.delimit(): + comma = False + for e in node.bases: + if comma: + self.write(", ") + else: + comma = True + self.traverse(e) + for e in node.keywords: + if comma: + self.write(", ") + else: + comma = True + self.traverse(e) with self.block(): self.traverse(node.body) @@ -812,10 +828,10 @@ def __FunctionDef_helper(self, node, fill_suffix): for deco in node.decorator_list: self.fill("@") self.traverse(deco) - def_str = fill_suffix + " " + node.name + "(" + def_str = fill_suffix + " " + node.name self.fill(def_str) - self.traverse(node.args) - self.write(")") + with self.delimit(): + self.traverse(node.args) if node.returns: self.write(" -> ") self.traverse(node.returns) @@ -931,13 +947,12 @@ def _write_constant(self, value): def visit_Constant(self, node): value = node.value if isinstance(value, tuple): - self.write("(") - if len(value) == 1: - self._write_constant(value[0]) - self.write(",") - else: - self.interleave(lambda: self.write(", "), self._write_constant, value) - self.write(")") + with self.delimit(): + if len(value) == 1: + self._write_constant(value[0]) + self.write(",") + else: + self.interleave(lambda: self.write(", "), self._write_constant, value) elif value is ...: self.write("...") else: @@ -946,39 +961,34 @@ def visit_Constant(self, node): self._write_constant(node.value) def visit_List(self, node): - self.write("[") - self.interleave(lambda: self.write(", "), self.traverse, node.elts) - self.write("]") + with self.delimit("[]"): + self.interleave(lambda: self.write(", "), self.traverse, node.elts) def visit_ListComp(self, node): - self.write("[") - self.traverse(node.elt) - for gen in node.generators: - self.traverse(gen) - self.write("]") + with self.delimit("[]"): + self.traverse(node.elt) + for gen in node.generators: + self.traverse(gen) def visit_GeneratorExp(self, node): - self.write("(") - self.traverse(node.elt) - for gen in node.generators: - self.traverse(gen) - self.write(")") + with self.delimit(): + self.traverse(node.elt) + for gen in node.generators: + self.traverse(gen) def visit_SetComp(self, node): - self.write("{") - self.traverse(node.elt) - for gen in node.generators: - self.traverse(gen) - self.write("}") + with self.delimit("{}"): + self.traverse(node.elt) + for gen in node.generators: + self.traverse(gen) def visit_DictComp(self, node): - self.write("{") - self.traverse(node.key) - self.write(": ") - self.traverse(node.value) - for gen in node.generators: - self.traverse(gen) - self.write("}") + with self.delimit("{}"): + self.traverse(node.key) + self.write(": ") + self.traverse(node.value) + for gen in node.generators: + self.traverse(gen) def visit_comprehension(self, node): if node.is_async: @@ -993,24 +1003,20 @@ def visit_comprehension(self, node): self.traverse(if_clause) def visit_IfExp(self, node): - self.write("(") - self.traverse(node.body) - self.write(" if ") - self.traverse(node.test) - self.write(" else ") - self.traverse(node.orelse) - self.write(")") + with self.delimit(): + self.traverse(node.body) + self.write(" if ") + self.traverse(node.test) + self.write(" else ") + self.traverse(node.orelse) def visit_Set(self, node): if not node.elts: raise ValueError("Set node should has at least one item") - self.write("{") - self.interleave(lambda: self.write(", "), self.traverse, node.elts) - self.write("}") + with self.delimit("{}"): + self.interleave(lambda: self.write(", "), self.traverse, node.elts) def visit_Dict(self, node): - self.write("{") - def write_key_value_pair(k, v): self.traverse(k) self.write(": ") @@ -1026,29 +1032,27 @@ def write_item(item): else: write_key_value_pair(k, v) - self.interleave( - lambda: self.write(", "), write_item, zip(node.keys, node.values) - ) - self.write("}") + with self.delimit("{}"): + self.interleave( + lambda: self.write(", "), write_item, zip(node.keys, node.values) + ) def visit_Tuple(self, node): - self.write("(") - if len(node.elts) == 1: - elt = node.elts[0] - self.traverse(elt) - self.write(",") - else: - self.interleave(lambda: self.write(", "), self.traverse, node.elts) - self.write(")") + with self.delimit(): + if len(node.elts) == 1: + elt = node.elts[0] + self.traverse(elt) + self.write(",") + else: + self.interleave(lambda: self.write(", "), self.traverse, node.elts) unop = {"Invert": "~", "Not": "not", "UAdd": "+", "USub": "-"} def visit_UnaryOp(self, node): - self.write("(") - self.write(self.unop[node.op.__class__.__name__]) - self.write(" ") - self.traverse(node.operand) - self.write(")") + with self.delimit(): + self.write(self.unop[node.op.__class__.__name__]) + self.write(" ") + self.traverse(node.operand) binop = { "Add": "+", @@ -1067,11 +1071,10 @@ def visit_UnaryOp(self, node): } def visit_BinOp(self, node): - self.write("(") - self.traverse(node.left) - self.write(" " + self.binop[node.op.__class__.__name__] + " ") - self.traverse(node.right) - self.write(")") + with self.delimit(): + self.traverse(node.left) + self.write(" " + self.binop[node.op.__class__.__name__] + " ") + self.traverse(node.right) cmpops = { "Eq": "==", @@ -1087,20 +1090,18 @@ def visit_BinOp(self, node): } def visit_Compare(self, node): - self.write("(") - self.traverse(node.left) - for o, e in zip(node.ops, node.comparators): - self.write(" " + self.cmpops[o.__class__.__name__] + " ") - self.traverse(e) - self.write(")") + with self.delimit(): + self.traverse(node.left) + for o, e in zip(node.ops, node.comparators): + self.write(" " + self.cmpops[o.__class__.__name__] + " ") + self.traverse(e) - boolops = {And: "and", Or: "or"} + boolops = {"And": "and", "Or": "or"} def visit_BoolOp(self, node): - self.write("(") - s = " %s " % self.boolops[node.op.__class__] - self.interleave(lambda: self.write(s), self.traverse, node.values) - self.write(")") + with self.delimit(): + s = " %s " % self.boolops[node.op.__class__.__name__] + self.interleave(lambda: self.write(s), self.traverse, node.values) def visit_Attribute(self, node): self.traverse(node.value) @@ -1114,27 +1115,25 @@ def visit_Attribute(self, node): def visit_Call(self, node): self.traverse(node.func) - self.write("(") - comma = False - for e in node.args: - if comma: - self.write(", ") - else: - comma = True - self.traverse(e) - for e in node.keywords: - if comma: - self.write(", ") - else: - comma = True - self.traverse(e) - self.write(")") + with self.delimit(): + comma = False + for e in node.args: + if comma: + self.write(", ") + else: + comma = True + self.traverse(e) + for e in node.keywords: + if comma: + self.write(", ") + else: + comma = True + self.traverse(e) def visit_Subscript(self, node): self.traverse(node.value) - self.write("[") - self.traverse(node.slice) - self.write("]") + with self.delimit("[]"): + self.traverse(node.slice) def visit_Starred(self, node): self.write("*") @@ -1228,12 +1227,11 @@ def visit_keyword(self, node): self.traverse(node.value) def visit_Lambda(self, node): - self.write("(") - self.write("lambda ") - self.traverse(node.args) - self.write(": ") - self.traverse(node.body) - self.write(")") + with self.delimit(): + self.write("lambda ") + self.traverse(node.args) + self.write(": ") + self.traverse(node.body) def visit_alias(self, node): self.write(node.name) diff --git a/Misc/NEWS.d/next/Library/2019-12-15-14-07-16.bpo-38870.8D28DB.rst b/Misc/NEWS.d/next/Library/2019-12-15-14-07-16.bpo-38870.8D28DB.rst new file mode 100644 index 000000000000000..1287081d0bfba89 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2019-12-15-14-07-16.bpo-38870.8D28DB.rst @@ -0,0 +1 @@ +Refactor delimiting in ``ast._Unparse`` with context managers. From ccbafcce0e600e860eaf63ceaee41e632693bf3a Mon Sep 17 00:00:00 2001 From: isidentical Date: Mon, 16 Dec 2019 10:38:10 +0300 Subject: [PATCH 2/5] remove delimit default --- Lib/ast.py | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/Lib/ast.py b/Lib/ast.py index a2b8815c79f3da2..387e8021e04a7e7 100644 --- a/Lib/ast.py +++ b/Lib/ast.py @@ -628,13 +628,13 @@ def __enter__(self): def __exit__(self, exc_type, exc_value, traceback): self.unparser.write(self.delimiter[-1]) - def delimit_if(self, condition, delimiter = "()"): + def delimit_if(self, condition, delimiter): if condition: return self._Delimit(self, delimiter) else: return self._NoDelimit() - def delimit(self, delimiter = "()"): + def delimit(self, delimiter): return self._Delimit(self, delimiter) def traverse(self, node): @@ -660,7 +660,7 @@ def visit_Expr(self, node): self.traverse(node.value) def visit_NamedExpr(self, node): - with self.delimit(): + with self.delimit("()"): self.traverse(node.target) self.write(" := ") self.traverse(node.value) @@ -735,21 +735,21 @@ def visit_Nonlocal(self, node): self.interleave(lambda: self.write(", "), self.write, node.names) def visit_Await(self, node): - with self.delimit(): + with self.delimit("()"): self.write("await") if node.value: self.write(" ") self.traverse(node.value) def visit_Yield(self, node): - with self.delimit(): + with self.delimit("()"): self.write("yield") if node.value: self.write(" ") self.traverse(node.value) def visit_YieldFrom(self, node): - with self.delimit(): + with self.delimit("()"): self.write("yield from") if node.value: self.write(" ") @@ -799,7 +799,7 @@ def visit_ClassDef(self, node): self.fill("@") self.traverse(deco) self.fill("class " + node.name) - with self.delimit(): + with self.delimit("()"): comma = False for e in node.bases: if comma: @@ -830,7 +830,7 @@ def __FunctionDef_helper(self, node, fill_suffix): self.traverse(deco) def_str = fill_suffix + " " + node.name self.fill(def_str) - with self.delimit(): + with self.delimit("()"): self.traverse(node.args) if node.returns: self.write(" -> ") @@ -947,7 +947,7 @@ def _write_constant(self, value): def visit_Constant(self, node): value = node.value if isinstance(value, tuple): - with self.delimit(): + with self.delimit("()"): if len(value) == 1: self._write_constant(value[0]) self.write(",") @@ -971,7 +971,7 @@ def visit_ListComp(self, node): self.traverse(gen) def visit_GeneratorExp(self, node): - with self.delimit(): + with self.delimit("()"): self.traverse(node.elt) for gen in node.generators: self.traverse(gen) @@ -1003,7 +1003,7 @@ def visit_comprehension(self, node): self.traverse(if_clause) def visit_IfExp(self, node): - with self.delimit(): + with self.delimit("()"): self.traverse(node.body) self.write(" if ") self.traverse(node.test) @@ -1038,7 +1038,7 @@ def write_item(item): ) def visit_Tuple(self, node): - with self.delimit(): + with self.delimit("()"): if len(node.elts) == 1: elt = node.elts[0] self.traverse(elt) @@ -1049,7 +1049,7 @@ def visit_Tuple(self, node): unop = {"Invert": "~", "Not": "not", "UAdd": "+", "USub": "-"} def visit_UnaryOp(self, node): - with self.delimit(): + with self.delimit("()"): self.write(self.unop[node.op.__class__.__name__]) self.write(" ") self.traverse(node.operand) @@ -1071,7 +1071,7 @@ def visit_UnaryOp(self, node): } def visit_BinOp(self, node): - with self.delimit(): + with self.delimit("()"): self.traverse(node.left) self.write(" " + self.binop[node.op.__class__.__name__] + " ") self.traverse(node.right) @@ -1090,7 +1090,7 @@ def visit_BinOp(self, node): } def visit_Compare(self, node): - with self.delimit(): + with self.delimit("()"): self.traverse(node.left) for o, e in zip(node.ops, node.comparators): self.write(" " + self.cmpops[o.__class__.__name__] + " ") @@ -1099,7 +1099,7 @@ def visit_Compare(self, node): boolops = {"And": "and", "Or": "or"} def visit_BoolOp(self, node): - with self.delimit(): + with self.delimit("()"): s = " %s " % self.boolops[node.op.__class__.__name__] self.interleave(lambda: self.write(s), self.traverse, node.values) @@ -1115,7 +1115,7 @@ def visit_Attribute(self, node): def visit_Call(self, node): self.traverse(node.func) - with self.delimit(): + with self.delimit("()"): comma = False for e in node.args: if comma: @@ -1227,7 +1227,7 @@ def visit_keyword(self, node): self.traverse(node.value) def visit_Lambda(self, node): - with self.delimit(): + with self.delimit("()"): self.write("lambda ") self.traverse(node.args) self.write(": ") From e1cb63f36a5a718ddaa89a4cddc54608ae828459 Mon Sep 17 00:00:00 2001 From: isidentical Date: Tue, 17 Dec 2019 00:48:19 +0300 Subject: [PATCH 3/5] refactor context manager with contextlib --- Lib/ast.py | 26 +++++++++----------------- 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/Lib/ast.py b/Lib/ast.py index 387e8021e04a7e7..db06dff07750935 100644 --- a/Lib/ast.py +++ b/Lib/ast.py @@ -26,6 +26,7 @@ """ import sys from _ast import * +from contextlib import contextmanager, nullcontext def parse(source, filename='', mode='exec', *, @@ -613,29 +614,20 @@ def __exit__(self, exc_type, exc_value, traceback): def block(self): return self._Block(self) - class _NoDelimit: - def __enter__(self): pass - def __exit__(self, *args): pass - - class _Delimit: + @contextmanager + def delimit(self, delimiter): """A context manager for preparing the source for expressions. It adds start of the delimiter and enters, after exit it adds delimiter end.""" - def __init__(self, unparser, delimiter): - self.unparser = unparser - self.delimiter = delimiter - def __enter__(self): - self.unparser.write(self.delimiter[0]) - def __exit__(self, exc_type, exc_value, traceback): - self.unparser.write(self.delimiter[-1]) + + self.write(delimiter[0]) + yield + self.write(delimiter[-1]) def delimit_if(self, condition, delimiter): if condition: - return self._Delimit(self, delimiter) + return self.delimit(delimiter) else: - return self._NoDelimit() - - def delimit(self, delimiter): - return self._Delimit(self, delimiter) + return nullcontext() def traverse(self, node): if isinstance(node, list): From a4cc6305206daf2522d9868ace0a997fb3c6126d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Batuhan=20Ta=C5=9Fkaya?= <47358913+isidentical@users.noreply.github.com> Date: Tue, 17 Dec 2019 11:11:57 +0300 Subject: [PATCH 4/5] documentaton improvements Co-Authored-By: Victor Stinner --- Lib/ast.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/ast.py b/Lib/ast.py index db06dff07750935..3dbe314563c51b3 100644 --- a/Lib/ast.py +++ b/Lib/ast.py @@ -617,7 +617,7 @@ def block(self): @contextmanager def delimit(self, delimiter): """A context manager for preparing the source for expressions. It adds - start of the delimiter and enters, after exit it adds delimiter end.""" + the first *delimiter* character at enters, adds the last *delimiter* character at exit.""" self.write(delimiter[0]) yield From 602704065a7a7ca7af9c2acbe6792338068f558d Mon Sep 17 00:00:00 2001 From: isidentical Date: Mon, 23 Dec 2019 18:34:27 +0300 Subject: [PATCH 5/5] instead of a whole string, use start= and end= parameters to take delimiter, remove news entry --- Lib/ast.py | 60 +++++++++---------- .../2019-12-15-14-07-16.bpo-38870.8D28DB.rst | 1 - 2 files changed, 30 insertions(+), 31 deletions(-) delete mode 100644 Misc/NEWS.d/next/Library/2019-12-15-14-07-16.bpo-38870.8D28DB.rst diff --git a/Lib/ast.py b/Lib/ast.py index db06dff07750935..355afc9a6250392 100644 --- a/Lib/ast.py +++ b/Lib/ast.py @@ -615,17 +615,17 @@ def block(self): return self._Block(self) @contextmanager - def delimit(self, delimiter): + def delimit(self, start, end): """A context manager for preparing the source for expressions. It adds - start of the delimiter and enters, after exit it adds delimiter end.""" + ``start`` to the buffer and enters, after exit it adds ``end``.""" - self.write(delimiter[0]) + self.write(start) yield - self.write(delimiter[-1]) + self.write(end) - def delimit_if(self, condition, delimiter): + def delimit_if(self, start, end, condition): if condition: - return self.delimit(delimiter) + return self.delimit(start, end) else: return nullcontext() @@ -652,7 +652,7 @@ def visit_Expr(self, node): self.traverse(node.value) def visit_NamedExpr(self, node): - with self.delimit("()"): + with self.delimit("(", ")"): self.traverse(node.target) self.write(" := ") self.traverse(node.value) @@ -684,7 +684,7 @@ def visit_AugAssign(self, node): def visit_AnnAssign(self, node): self.fill() - with self.delimit_if(not node.simple and isinstance(node.target, Name)): + with self.delimit_if("(", ")", not node.simple and isinstance(node.target, Name)): self.traverse(node.target) self.write(": ") self.traverse(node.annotation) @@ -727,21 +727,21 @@ def visit_Nonlocal(self, node): self.interleave(lambda: self.write(", "), self.write, node.names) def visit_Await(self, node): - with self.delimit("()"): + with self.delimit("(", ")"): self.write("await") if node.value: self.write(" ") self.traverse(node.value) def visit_Yield(self, node): - with self.delimit("()"): + with self.delimit("(", ")"): self.write("yield") if node.value: self.write(" ") self.traverse(node.value) def visit_YieldFrom(self, node): - with self.delimit("()"): + with self.delimit("(", ")"): self.write("yield from") if node.value: self.write(" ") @@ -791,7 +791,7 @@ def visit_ClassDef(self, node): self.fill("@") self.traverse(deco) self.fill("class " + node.name) - with self.delimit("()"): + with self.delimit("(", ")"): comma = False for e in node.bases: if comma: @@ -822,7 +822,7 @@ def __FunctionDef_helper(self, node, fill_suffix): self.traverse(deco) def_str = fill_suffix + " " + node.name self.fill(def_str) - with self.delimit("()"): + with self.delimit("(", ")"): self.traverse(node.args) if node.returns: self.write(" -> ") @@ -939,7 +939,7 @@ def _write_constant(self, value): def visit_Constant(self, node): value = node.value if isinstance(value, tuple): - with self.delimit("()"): + with self.delimit("(", ")"): if len(value) == 1: self._write_constant(value[0]) self.write(",") @@ -953,29 +953,29 @@ def visit_Constant(self, node): self._write_constant(node.value) def visit_List(self, node): - with self.delimit("[]"): + with self.delimit("[", "]"): self.interleave(lambda: self.write(", "), self.traverse, node.elts) def visit_ListComp(self, node): - with self.delimit("[]"): + with self.delimit("[", "]"): self.traverse(node.elt) for gen in node.generators: self.traverse(gen) def visit_GeneratorExp(self, node): - with self.delimit("()"): + with self.delimit("(", ")"): self.traverse(node.elt) for gen in node.generators: self.traverse(gen) def visit_SetComp(self, node): - with self.delimit("{}"): + with self.delimit("{", "}"): self.traverse(node.elt) for gen in node.generators: self.traverse(gen) def visit_DictComp(self, node): - with self.delimit("{}"): + with self.delimit("{", "}"): self.traverse(node.key) self.write(": ") self.traverse(node.value) @@ -995,7 +995,7 @@ def visit_comprehension(self, node): self.traverse(if_clause) def visit_IfExp(self, node): - with self.delimit("()"): + with self.delimit("(", ")"): self.traverse(node.body) self.write(" if ") self.traverse(node.test) @@ -1005,7 +1005,7 @@ def visit_IfExp(self, node): def visit_Set(self, node): if not node.elts: raise ValueError("Set node should has at least one item") - with self.delimit("{}"): + with self.delimit("{", "}"): self.interleave(lambda: self.write(", "), self.traverse, node.elts) def visit_Dict(self, node): @@ -1024,13 +1024,13 @@ def write_item(item): else: write_key_value_pair(k, v) - with self.delimit("{}"): + with self.delimit("{", "}"): self.interleave( lambda: self.write(", "), write_item, zip(node.keys, node.values) ) def visit_Tuple(self, node): - with self.delimit("()"): + with self.delimit("(", ")"): if len(node.elts) == 1: elt = node.elts[0] self.traverse(elt) @@ -1041,7 +1041,7 @@ def visit_Tuple(self, node): unop = {"Invert": "~", "Not": "not", "UAdd": "+", "USub": "-"} def visit_UnaryOp(self, node): - with self.delimit("()"): + with self.delimit("(", ")"): self.write(self.unop[node.op.__class__.__name__]) self.write(" ") self.traverse(node.operand) @@ -1063,7 +1063,7 @@ def visit_UnaryOp(self, node): } def visit_BinOp(self, node): - with self.delimit("()"): + with self.delimit("(", ")"): self.traverse(node.left) self.write(" " + self.binop[node.op.__class__.__name__] + " ") self.traverse(node.right) @@ -1082,7 +1082,7 @@ def visit_BinOp(self, node): } def visit_Compare(self, node): - with self.delimit("()"): + with self.delimit("(", ")"): self.traverse(node.left) for o, e in zip(node.ops, node.comparators): self.write(" " + self.cmpops[o.__class__.__name__] + " ") @@ -1091,7 +1091,7 @@ def visit_Compare(self, node): boolops = {"And": "and", "Or": "or"} def visit_BoolOp(self, node): - with self.delimit("()"): + with self.delimit("(", ")"): s = " %s " % self.boolops[node.op.__class__.__name__] self.interleave(lambda: self.write(s), self.traverse, node.values) @@ -1107,7 +1107,7 @@ def visit_Attribute(self, node): def visit_Call(self, node): self.traverse(node.func) - with self.delimit("()"): + with self.delimit("(", ")"): comma = False for e in node.args: if comma: @@ -1124,7 +1124,7 @@ def visit_Call(self, node): def visit_Subscript(self, node): self.traverse(node.value) - with self.delimit("[]"): + with self.delimit("[", "]"): self.traverse(node.slice) def visit_Starred(self, node): @@ -1219,7 +1219,7 @@ def visit_keyword(self, node): self.traverse(node.value) def visit_Lambda(self, node): - with self.delimit("()"): + with self.delimit("(", ")"): self.write("lambda ") self.traverse(node.args) self.write(": ") diff --git a/Misc/NEWS.d/next/Library/2019-12-15-14-07-16.bpo-38870.8D28DB.rst b/Misc/NEWS.d/next/Library/2019-12-15-14-07-16.bpo-38870.8D28DB.rst deleted file mode 100644 index 1287081d0bfba89..000000000000000 --- a/Misc/NEWS.d/next/Library/2019-12-15-14-07-16.bpo-38870.8D28DB.rst +++ /dev/null @@ -1 +0,0 @@ -Refactor delimiting in ``ast._Unparse`` with context managers.