diff --git a/jedi/api/__init__.py b/jedi/api/__init__.py index d72260f2..75bf964f 100644 --- a/jedi/api/__init__.py +++ b/jedi/api/__init__.py @@ -157,6 +157,7 @@ class Script(object): last word part. To ignore certain strange patterns with dots, just use regex. """ + if re.match('\d+\.\.$|\.{4}$', path): return True # check Ellipsis and float literal `1.` @@ -164,8 +165,9 @@ class Script(object): debug.speed('completions start') path = self._user_context.get_path_until_cursor() - if not completion_possible(path): - return [] + # TODO still needed with the new parser? + #if not completion_possible(path): + # return [] path, dot, like = helpers.completion_parts(path) user_stmt = self._parser.user_stmt_with_whitespace() diff --git a/jedi/api/helpers.py b/jedi/api/helpers.py index 7baf7609..c69fd1ca 100644 --- a/jedi/api/helpers.py +++ b/jedi/api/helpers.py @@ -36,24 +36,30 @@ def get_on_import_stmt(evaluator, user_context, user_stmt, is_like_search=False) def check_error_statements(evaluator, module, pos): for error_statement in module.error_statement_stacks: - if error_statement.first_type in ('import_from' or 'import_name') \ + if error_statement.first_type in ('import_from', 'import_name') \ and error_statement.first_pos < pos <= error_statement.next_start_pos: return importer_from_error_statement(evaluator, module, error_statement, pos) return None def importer_from_error_statement(evaluator, module, error_statement, pos): + def check_dotted(children): + for name in children[::2]: + if name.end_pos < pos: + yield name + names = [] level = 0 for typ, nodes in error_statement.stack: if typ == 'dotted_name': - names += nodes[::2] + names += check_dotted(nodes) elif typ == 'import_from': for node in nodes: if isinstance(node, pt.Node) and node.type == 'dotted_name': - names += node.children[::2] - print(typ, nodes) - - print('x', names) + names += check_dotted(node.children[::2]) + elif node in ('.', '...'): + level += len(node.value) + elif isinstance(node, pt.Name) and node.end_pos < pos: + names.append(node) return imports.get_importer(evaluator, names, module, level) diff --git a/jedi/evaluate/imports.py b/jedi/evaluate/imports.py index 9292ec10..ec3ff0ca 100644 --- a/jedi/evaluate/imports.py +++ b/jedi/evaluate/imports.py @@ -54,7 +54,8 @@ class ImportWrapper(pr.Base): module = self._import.get_parent_until() importer = get_importer(self._evaluator, tuple(import_path), module, self._import.level) - return importer.completion_names(self._evaluator) + only_modules = isinstance(self._import, pr.ImportName) + return importer.completion_names(self._evaluator, only_modules) @memoize_default() def follow(self, is_goto=False): @@ -91,7 +92,7 @@ class ImportWrapper(pr.Base): # follow the rest of the import (not FS -> classes, functions) if len(rest) > 1 or rest and self.is_like_search: - if ('os', 'path') == importer.str_import_path()[:2] \ + if ('os', 'path') == importer.str_import_path[:2] \ and self._import.level == 0: # This is a huge exception, we follow a nested import # ``os.path``, because it's a very important one in Python @@ -443,7 +444,10 @@ class _Importer(object): return in_path + sys_path_with_modifications(self._evaluator, self.module) def follow(self, evaluator): - scope, rest = self.follow_file_system() + try: + scope, rest = self.follow_file_system() + except ModuleNotFound: + return [] if rest: # follow the rest of the import (not FS -> classes, functions) return [] @@ -653,7 +657,6 @@ class _Importer(object): if only_modules: # In the case of an import like `from x.` we don't need to # add all the variables. - print(self.import_path) if ('os',) == self.str_import_path and not self.level: # os.path is a hardcoded exception, because it's a # ``sys.modules`` modification. diff --git a/test/completion/on_import.py b/test/completion/on_import.py index a2ec198a..557bfaaa 100644 --- a/test/completion/on_import.py +++ b/test/completion/on_import.py @@ -71,6 +71,13 @@ from import_tree.p import pkg from .import_tree import #? 10 ['run'] from ..run import +#? ['run'] +from ..run +#? 10 ['run'] +from ..run. +#? [] +from ..run. + #? ['run'] from .. import run