diff --git a/jedi/api/file_name.py b/jedi/api/file_name.py index 3e21de49..01e24d1c 100644 --- a/jedi/api/file_name.py +++ b/jedi/api/file_name.py @@ -1,5 +1,7 @@ import os +from parso.tree import search_ancestor + from jedi._compatibility import FileNotFoundError, force_unicode from jedi.evaluate.names import AbstractArbitraryName from jedi.api import classes @@ -109,14 +111,12 @@ def _add_os_path_join(module_context, start_leaf, bracket_start): context = module_context.create_context(nodes[0]) return _add_strings(context, nodes, add_slash=True) or '' - # Maybe an arglist or some weird error case. Therefore checked below. - arglist = start_leaf.parent - index = arglist.children.index(start_leaf) - arglist_nodes = arglist.children[:index] if start_leaf.type == 'error_leaf': # Unfinished string literal, like `join('` + context_node = start_leaf.parent + index = context_node.children.index(start_leaf) if index > 0: - error_node = arglist_nodes[-1] + error_node = context_node.children[index - 1] if error_node.type == 'error_node' and len(error_node.children) >= 2: index = -2 if error_node.children[-1].type == 'arglist': @@ -126,19 +126,33 @@ def _add_os_path_join(module_context, start_leaf, bracket_start): arglist_nodes = [] return check(error_node.children[index + 1], arglist_nodes[::2]) - elif arglist.type == 'arglist': - trailer = arglist.parent + return None + + # Maybe an arglist or some weird error case. Therefore checked below. + searched_node_child = start_leaf + while searched_node_child.parent is not None \ + and searched_node_child.parent.type not in ('arglist', 'trailer', 'error_node'): + searched_node_child = searched_node_child.parent + + if searched_node_child.get_first_leaf() is not start_leaf: + return None + searched_node = searched_node_child.parent + if searched_node is None: + return None + + index = searched_node.children.index(searched_node_child) + arglist_nodes = searched_node.children[:index] + if searched_node.type == 'arglist': + trailer = searched_node.parent if trailer.type == 'error_node': - trailer_index = trailer.children.index(arglist) + trailer_index = trailer.children.index(searched_node) assert trailer_index >= 2 assert trailer.children[trailer_index - 1] == '(' return check(trailer.children[trailer_index - 1], arglist_nodes[::2]) elif trailer.type == 'trailer': return check(trailer.children[0], arglist_nodes[::2]) - elif arglist.type == 'trailer': - return check(arglist.children[0], []) - elif arglist.type == 'error_node': + elif searched_node.type == 'trailer': + return check(searched_node.children[0], []) + elif searched_node.type == 'error_node': # Stuff like `join(""` return check(arglist_nodes[-1], []) - - return None diff --git a/test/test_api/test_completion.py b/test/test_api/test_completion.py index 95803c53..a9dc66e1 100644 --- a/test/test_api/test_completion.py +++ b/test/test_api/test_completion.py @@ -247,6 +247,7 @@ os_path = 'from os.path import *\n' (f2, os_path + 'join(["tes', 10, ['t' + s]), (f2, os_path + 'join(["tes"]', 10, ['t' + s]), (f2, os_path + 'join(["tes"])', 10, ['t' + s]), + (f2, os_path + 'join("test", "test_cac" + x,', 22, ['he.py"']), ] ) def test_file_path_completions(Script, file, code, column, expected):