Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 83e496f

Browse files
author
Ben Caller
committed
Make get_call_names more resilient
Code where we call a method of something which isn't a variable name e.g. ``` yesterday = (date.today() - timedelta(days=1)).strftime("%Y-%m-%d") ``` was causing pyt to crash. Previously the else branch would only handle ast.Attribute, and crash on everything else. ``` Traceback (most recent call last): File "/usr/lib/python3.6/runpy.py", line 193, in _run_module_as_main "__main__", mod_spec) File "/usr/lib/python3.6/runpy.py", line 85, in _run_code exec(code, run_globals) File "/pyt/pyt/__main__.py", line 141, in <module> main() File "/pyt/pyt/__main__.py", line 97, in main path File "/pyt/pyt/cfg/make_cfg.py", line 40, in make_cfg module_definitions File "/pyt/pyt/cfg/expr_visitor.py", line 60, in __init__ self.init_cfg(node) File "/pyt/pyt/cfg/expr_visitor.py", line 67, in init_cfg module_statements = self.visit(node) File "/usr/lib/python3.6/ast.py", line 253, in visit return visitor(node) File "/pyt/pyt/cfg/stmt_visitor.py", line 58, in visit_Module return self.stmt_star_handler(node.body) File "/pyt/pyt/cfg/stmt_visitor.py", line 79, in stmt_star_handler node = self.visit(stmt) File "/usr/lib/python3.6/ast.py", line 253, in visit return visitor(node) File "/pyt/pyt/cfg/stmt_visitor.py", line 413, in visit_Assign return self.assignment_call_node(label.result, node) File "/pyt/pyt/cfg/stmt_visitor.py", line 437, in assignment_call_node call = self.visit(ast_node.value) File "/usr/lib/python3.6/ast.py", line 253, in visit return visitor(node) File "/pyt/pyt/cfg/expr_visitor.py", line 540, in visit_Call _id = get_call_names_as_string(node.func) File "/pyt/pyt/core/ast_helper.py", line 78, in get_call_names_as_string return _list_to_dotted_string(get_call_names(node)) File "/pyt/pyt/core/ast_helper.py", line 68, in get_call_names return reversed(_get_call_names_helper(node, result)) File "/pyt/pyt/core/ast_helper.py", line 62, in _get_call_names_helper return _get_call_names_helper(node.value, result) File "/pyt/pyt/core/ast_helper.py", line 61, in _get_call_names_helper result.append(node.attr) AttributeError: 'BinOp' object has no attribute 'attr' ```
1 parent e692581 commit 83e496f

2 files changed

Lines changed: 24 additions & 13 deletions

File tree

pyt/core/ast_helper.py

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -44,28 +44,23 @@ def generate_ast(path):
4444
raise IOError('Input needs to be a file. Path: ' + path)
4545

4646

47-
def _get_call_names_helper(node, result):
47+
def _get_call_names_helper(node):
4848
"""Recursively finds all function names."""
4949
if isinstance(node, ast.Name):
5050
if node.id not in BLACK_LISTED_CALL_NAMES:
51-
result.append(node.id)
52-
return result
53-
elif isinstance(node, ast.Call):
54-
return result
51+
yield node.id
5552
elif isinstance(node, ast.Subscript):
56-
return _get_call_names_helper(node.value, result)
53+
yield from _get_call_names_helper(node.value)
5754
elif isinstance(node, ast.Str):
58-
result.append(node.s)
59-
return result
60-
else:
61-
result.append(node.attr)
62-
return _get_call_names_helper(node.value, result)
55+
yield node.s
56+
elif isinstance(node, ast.Attribute):
57+
yield node.attr
58+
yield from _get_call_names_helper(node.value)
6359

6460

6561
def get_call_names(node):
6662
"""Get a list of call names."""
67-
result = list()
68-
return reversed(_get_call_names_helper(node, result))
63+
return reversed(list(_get_call_names_helper(node)))
6964

7065

7166
def _list_to_dotted_string(list_of_components):

tests/cfg/import_test.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -733,3 +733,19 @@ def test_get_call_names_multi(self):
733733
result = get_call_names_as_string(call.func)
734734

735735
self.assertEqual(result, 'abc.defg.hi')
736+
737+
def test_get_call_names_with_binop(self):
738+
m = ast.parse('(date.today() - timedelta(days=1)).strftime("%Y-%m-%d")')
739+
call = m.body[0].value
740+
741+
result = get_call_names_as_string(call.func)
742+
743+
self.assertEqual(result, 'strftime')
744+
745+
def test_get_call_names_with_comprehension(self):
746+
m = ast.parse('{a for a in b()}.union(c)')
747+
call = m.body[0].value
748+
749+
result = get_call_names_as_string(call.func)
750+
751+
self.assertEqual(result, 'union')

0 commit comments

Comments
 (0)