unparser: Don't omit parenthesis when unparsing a slice
Backport of
c102a14825
Includes support for Python 2.
This commit is contained in:
parent
0776c3b4d6
commit
39afe946a0
1 changed files with 39 additions and 14 deletions
|
@ -65,6 +65,22 @@ def interleave(inter, f, seq):
|
||||||
f(x)
|
f(x)
|
||||||
|
|
||||||
|
|
||||||
|
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, ast.Tuple)
|
||||||
|
and slice_value.elts
|
||||||
|
and (
|
||||||
|
# Python 2 doesn't allow starred elements in tuples like Python 3
|
||||||
|
six.PY2 or not any(
|
||||||
|
isinstance(elt, ast.Starred) for elt in slice_value.elts
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class Unparser:
|
class Unparser:
|
||||||
"""Methods in this class recursively traverse an AST and
|
"""Methods in this class recursively traverse an AST and
|
||||||
output source code for the abstract syntax; original formatting
|
output source code for the abstract syntax; original formatting
|
||||||
|
@ -103,6 +119,16 @@ def __init__(self, py_ver_consistent=False):
|
||||||
self._py_ver_consistent = py_ver_consistent
|
self._py_ver_consistent = py_ver_consistent
|
||||||
self._precedences = {}
|
self._precedences = {}
|
||||||
|
|
||||||
|
def items_view(self, traverser, items):
|
||||||
|
"""Traverse and separate the given *items* with a comma and append it to
|
||||||
|
the buffer. If *items* is a single item sequence, a trailing comma
|
||||||
|
will be added."""
|
||||||
|
if len(items) == 1:
|
||||||
|
traverser(items[0])
|
||||||
|
self.write(",")
|
||||||
|
else:
|
||||||
|
interleave(lambda: self.write(", "), traverser, items)
|
||||||
|
|
||||||
def visit(self, tree, output_file):
|
def visit(self, tree, output_file):
|
||||||
"""Traverse tree and write source code to output_file."""
|
"""Traverse tree and write source code to output_file."""
|
||||||
self.f = output_file
|
self.f = output_file
|
||||||
|
@ -657,11 +683,7 @@ def _Constant(self, t):
|
||||||
value = t.value
|
value = t.value
|
||||||
if isinstance(value, tuple):
|
if isinstance(value, tuple):
|
||||||
with self.delimit("(", ")"):
|
with self.delimit("(", ")"):
|
||||||
if len(value) == 1:
|
self.items_view(self._write_constant, value)
|
||||||
self._write_constant(value[0])
|
|
||||||
self.write(",")
|
|
||||||
else:
|
|
||||||
interleave(lambda: self.write(", "), self._write_constant, value)
|
|
||||||
elif value is Ellipsis: # instead of `...` for Py2 compatibility
|
elif value is Ellipsis: # instead of `...` for Py2 compatibility
|
||||||
self.write("...")
|
self.write("...")
|
||||||
else:
|
else:
|
||||||
|
@ -762,12 +784,7 @@ def write_item(item):
|
||||||
|
|
||||||
def _Tuple(self, t):
|
def _Tuple(self, t):
|
||||||
with self.delimit("(", ")"):
|
with self.delimit("(", ")"):
|
||||||
if len(t.elts) == 1:
|
self.items_view(self.dispatch, t.elts)
|
||||||
elt = t.elts[0]
|
|
||||||
self.dispatch(elt)
|
|
||||||
self.write(",")
|
|
||||||
else:
|
|
||||||
interleave(lambda: self.write(", "), self.dispatch, t.elts)
|
|
||||||
|
|
||||||
unop = {
|
unop = {
|
||||||
"Invert": "~",
|
"Invert": "~",
|
||||||
|
@ -974,7 +991,10 @@ def _Subscript(self, t):
|
||||||
self.set_precedence(_Precedence.ATOM, t.value)
|
self.set_precedence(_Precedence.ATOM, t.value)
|
||||||
self.dispatch(t.value)
|
self.dispatch(t.value)
|
||||||
with self.delimit("[", "]"):
|
with self.delimit("[", "]"):
|
||||||
self.dispatch(t.slice)
|
if is_simple_tuple(t.slice):
|
||||||
|
self.items_view(self.dispatch, t.slice.elts)
|
||||||
|
else:
|
||||||
|
self.dispatch(t.slice)
|
||||||
|
|
||||||
def _Starred(self, t):
|
def _Starred(self, t):
|
||||||
self.write("*")
|
self.write("*")
|
||||||
|
@ -985,9 +1005,14 @@ def _Starred(self, t):
|
||||||
def _Ellipsis(self, t):
|
def _Ellipsis(self, t):
|
||||||
self.write("...")
|
self.write("...")
|
||||||
|
|
||||||
|
# used in Python <= 3.8 -- see _Subscript for 3.9+
|
||||||
def _Index(self, t):
|
def _Index(self, t):
|
||||||
self.set_precedence(_Precedence.TUPLE, t.value)
|
if is_simple_tuple(t.value):
|
||||||
self.dispatch(t.value)
|
self.set_precedence(_Precedence.ATOM, t.value)
|
||||||
|
self.items_view(self.dispatch, t.value.elts)
|
||||||
|
else:
|
||||||
|
self.set_precedence(_Precedence.TUPLE, t.value)
|
||||||
|
self.dispatch(t.value)
|
||||||
|
|
||||||
def _Slice(self, t):
|
def _Slice(self, t):
|
||||||
if t.lower:
|
if t.lower:
|
||||||
|
|
Loading…
Reference in a new issue