Kaydet (Commit) 48b79ddd authored tarafından Anthony Sottile's avatar Anthony Sottile

Special case handling tuples

üst c7da498e
...@@ -63,11 +63,12 @@ class FindNodes(ast.NodeVisitor): ...@@ -63,11 +63,12 @@ class FindNodes(ast.NodeVisitor):
self.calls = collections.defaultdict(list) self.calls = collections.defaultdict(list)
self.funcs = {} self.funcs = {}
self.literals = {} self.literals = {}
self.tuples = {}
def _visit_literal(self, node, key='elts', **kwargs): def _visit_literal(self, node, key='elts'):
if getattr(node, key): if getattr(node, key):
key = Offset(node.lineno, node.col_offset) key = Offset(node.lineno, node.col_offset)
self.literals[key] = Literal(node, **kwargs) self.literals[key] = Literal(node)
self.generic_visit(node) self.generic_visit(node)
visit_Set = visit_List = _visit_literal visit_Set = visit_List = _visit_literal
...@@ -76,8 +77,11 @@ class FindNodes(ast.NodeVisitor): ...@@ -76,8 +77,11 @@ class FindNodes(ast.NodeVisitor):
self._visit_literal(node, key='values') self._visit_literal(node, key='values')
def visit_Tuple(self, node): def visit_Tuple(self, node):
# tuples lie about things so we tell the later machiner to backtrack if node.elts:
self._visit_literal(node, backtrack=True) key = Offset(node.lineno, node.col_offset)
# tuples lie about offset -- tell the later machinery to backtrack
self.tuples[key] = Literal(node, backtrack=True)
self.generic_visit(node)
def visit_Call(self, node): def visit_Call(self, node):
argnodes = node.args + node.keywords argnodes = node.args + node.keywords
...@@ -200,16 +204,15 @@ def _find_call(call, i, tokens): ...@@ -200,16 +204,15 @@ def _find_call(call, i, tokens):
return _find_simple(first_brace, tokens) return _find_simple(first_brace, tokens)
def _find_literal(literal, i, tokens): def _find_tuple(i, tokens):
# tuples are evil, we need to backtrack to find the opening paren # tuples are evil, we need to backtrack to find the opening paren
if literal.backtrack: i -= 1
while tokens[i].name in NON_CODING_TOKENS:
i -= 1 i -= 1
while tokens[i].name in NON_CODING_TOKENS: # Sometimes tuples don't even have a paren!
i -= 1 # x = 1, 2, 3
# Sometimes tuples don't even have a paren! if tokens[i].src != '(':
# x = 1, 2, 3 return
if tokens[i].src != '(':
return
return _find_simple(i, tokens) return _find_simple(i, tokens)
...@@ -326,13 +329,14 @@ def _fix_src(contents_text, py35_plus): ...@@ -326,13 +329,14 @@ def _fix_src(contents_text, py35_plus):
# Handle parenthesized things # Handle parenthesized things
elif token.src == '(': elif token.src == '(':
fixes.append((False, _find_simple(i, tokens))) fixes.append((False, _find_simple(i, tokens)))
elif key in visitor.literals:
fixes.append((True, _find_simple(i, tokens)))
# need to additionally handle literals afterwards as tuples report # need to additionally handle literals afterwards as tuples report
# their starting index as the first element, which may be one of the # their starting index as the first element, which may be one of the
# above things. # above things.
if key in visitor.literals: if key in visitor.tuples:
fix_data = _find_literal(visitor.literals[key], i, tokens) fixes.append((True, _find_tuple(i, tokens)))
fixes.append((True, fix_data))
for add_comma, fix_data in fixes: for add_comma, fix_data in fixes:
if fix_data is not None: if fix_data is not None:
......
...@@ -124,6 +124,18 @@ def test_py35_plus_rewrite(): ...@@ -124,6 +124,18 @@ def test_py35_plus_rewrite():
' x,\n' ' x,\n'
')', ')',
), ),
# Regression test for #23
(
'(\n'
' {k: v},\n'
' ()\n'
')',
'(\n'
' {k: v},\n'
' (),\n'
')',
),
), ),
) )
def test_fixes_calls(src, expected): def test_fixes_calls(src, expected):
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment