diff --git a/jedi/api/__init__.py b/jedi/api/__init__.py index 618bf1ba..a1cb9ac0 100644 --- a/jedi/api/__init__.py +++ b/jedi/api/__init__.py @@ -338,7 +338,7 @@ class Script(object): if node.is_nested(): import_names |= set(path[-1] for path in node.paths()) for n in import_names: - imports.ImportWrapper(context, n).follow() + imports.infer_import(context, n) elif node.type == 'expr_stmt': types = context.eval_node(node) for testlist in node.children[:-1:2]: diff --git a/jedi/api/classes.py b/jedi/api/classes.py index b86ce09d..fb3d085d 100644 --- a/jedi/api/classes.py +++ b/jedi/api/classes.py @@ -500,8 +500,7 @@ class Completion(BaseDefinition): definition = self._definition if definition.isinstance(tree.Import): raise DeprecationWarning - i = imports.ImportWrapper(self._evaluator, self._name) - return i.follow() + return imports.infer_import(self._evaluator, self._name) return super(Completion, self)._follow_statements_imports() @memoize_method diff --git a/jedi/api/usages.py b/jedi/api/usages.py index 9519c0b1..d0dff5b1 100644 --- a/jedi/api/usages.py +++ b/jedi/api/usages.py @@ -59,6 +59,10 @@ def resolve_potential_imports(evaluator, definitions): if isinstance(d, TreeNameDefinition): imp_or_stmt = d.tree_name.get_definition() if isinstance(imp_or_stmt, tree.Import): - s = imports.ImportWrapper(d.parent_context, d.tree_name) - new |= resolve_potential_imports(evaluator, set(s.follow(is_goto=True))) + new |= resolve_potential_imports( + evaluator, + set(imports.infer_import( + d.parent_context, d.tree_name, is_goto=True + )) + ) return set(definitions) | new diff --git a/jedi/evaluate/__init__.py b/jedi/evaluate/__init__.py index ea4efacd..85f60df1 100644 --- a/jedi/evaluate/__init__.py +++ b/jedi/evaluate/__init__.py @@ -451,21 +451,11 @@ class Evaluator(object): for_types = iterable.py__iter__types(self, container_types, def_.children[3]) return finder.check_tuple_assignments(self, for_types, name) elif def_.type in ('import_from', 'import_name'): - return imports.ImportWrapper(context, name).follow() + return imports.infer_import(context, name) return helpers.evaluate_call_of_leaf(context, name) def goto(self, context, name): - def resolve_implicit_imports(names): - for name in names: - if isinstance(name.parent, helpers.FakeImport): - # Those are implicit imports. - s = imports.ImportWrapper(context, name) - for n in s.follow(is_goto=True): - yield n - else: - yield name - stmt = name.get_definition() par = name.parent if par.type == 'argument' and par.children[1] == '=' and par.children[0] == name: @@ -500,9 +490,8 @@ class Evaluator(object): elif isinstance(par, (tree.Param, tree.Function, tree.Class)) and par.name is name: return [TreeNameDefinition(context, name)] elif isinstance(stmt, tree.Import): - module_names = imports.ImportWrapper(context, name).follow(is_goto=True) + module_names = imports.infer_import(context, name, is_goto=True) return module_names - return list(resolve_implicit_imports(module_names)) elif par.type == 'dotted_name': # Is a decorator. index = par.children.index(name) if index > 0: @@ -513,9 +502,6 @@ class Evaluator(object): value.py__getattribute__(name, name_context=context, is_goto=True) for value in values ) - #return resolve_implicit_imports(iterable.unite( - #self.find_types(typ, name, is_goto=True) for typ in types - #)) if tree.is_node(par, 'trailer') and par.children[0] == '.': values = helpers.evaluate_call_of_leaf(context, name, cut_own_trailer=True) @@ -523,9 +509,6 @@ class Evaluator(object): value.py__getattribute__(name, name_context=context, is_goto=True) for value in values ) - #return resolve_implicit_imports(iterable.unite( - #self.find_types(typ, name, is_goto=True) for typ in types - #)) else: if stmt.type != 'expr_stmt': # We only need to adjust the start_pos for statements, because diff --git a/jedi/evaluate/finder.py b/jedi/evaluate/finder.py index c3321e5c..97e6274f 100644 --- a/jedi/evaluate/finder.py +++ b/jedi/evaluate/finder.py @@ -362,7 +362,7 @@ def _name_to_types(evaluator, context, name): elif node.isinstance(tree.WithStmt): types = context.eval_node(node.node_from_name(name)) elif isinstance(node, tree.Import): - types = imports.ImportWrapper(context, name).follow() + types = imports.infer_import(context, name) elif node.type in ('funcdef', 'classdef'): types = _apply_decorators(evaluator, context, node) elif node.type == 'global_stmt': diff --git a/jedi/evaluate/imports.py b/jedi/evaluate/imports.py index ecce2c6b..847c8ac5 100644 --- a/jedi/evaluate/imports.py +++ b/jedi/evaluate/imports.py @@ -56,63 +56,56 @@ def completion_names(evaluator, imp, pos): return importer.completion_names(evaluator, only_modules) -class ImportWrapper(object): - def __init__(self, context, name): - self._context = context - self._name = name +def infer_import(context, tree_name, is_goto=False): + module_context = context.get_root_context() + import_node = tree_name.get_parent_until(tree.Import) + import_path = import_node.path_for_name(tree_name) + from_import_name = None + evaluator = context.evaluator + try: + from_names = import_node.get_from_names() + except AttributeError: + # Is an import_name + pass + else: + if len(from_names) + 1 == len(import_path): + # We have to fetch the from_names part first and then check + # if from_names exists in the modules. + from_import_name = import_path[-1] + import_path = from_names - # TODO move this whole thing to a function - def follow(self, is_goto=False): - module_context = self._context.get_root_context() - import_node = self._name.get_parent_until(tree.Import) - import_path = import_node.path_for_name(self._name) - from_import_name = None - evaluator = self._context.evaluator - try: - from_names = import_node.get_from_names() - except AttributeError: - # Is an import_name - pass - else: - if len(from_names) + 1 == len(import_path): - # We have to fetch the from_names part first and then check - # if from_names exists in the modules. - from_import_name = import_path[-1] - import_path = from_names + importer = Importer(evaluator, tuple(import_path), + module_context, import_node.level) - importer = Importer(evaluator, tuple(import_path), - module_context, import_node.level) + types = importer.follow() - # TODO This is terrible, why different Importer instances? - types = importer.follow() + #if import_node.is_nested() and not self.nested_resolve: + # scopes = [NestedImportModule(module, import_node)] - #if import_node.is_nested() and not self.nested_resolve: - # scopes = [NestedImportModule(module, import_node)] + if from_import_name is not None: + types = unite( + t.py__getattribute__( + unicode(from_import_name), + name_context=context, + is_goto=is_goto + ) for t in types + ) - if from_import_name is not None: - types = unite( - t.py__getattribute__( - unicode(from_import_name), - name_context=self._context, - is_goto=is_goto - ) for t in types - ) - - if not types: - path = import_path + [from_import_name] - importer = Importer(evaluator, tuple(path), - module_context, import_node.level) - types = importer.follow() - # goto only accepts `Name` - if is_goto: - types = set(s.name for s in types) - else: + if not types: + path = import_path + [from_import_name] + importer = Importer(evaluator, tuple(path), + module_context, import_node.level) + types = importer.follow() # goto only accepts `Name` if is_goto: types = set(s.name for s in types) + else: + # goto only accepts `Name` + if is_goto: + types = set(s.name for s in types) - debug.dbg('after import: %s', types) - return types + debug.dbg('after import: %s', types) + return types class NestedImportModule(tree.Module): diff --git a/jedi/evaluate/representation.py b/jedi/evaluate/representation.py index d863584c..10287c2d 100644 --- a/jedi/evaluate/representation.py +++ b/jedi/evaluate/representation.py @@ -505,7 +505,7 @@ class ModuleContext(use_metaclass(CachedMetaClass, context.TreeContext)): for i in self.module_node.imports: if i.is_star_import(): name = i.star_import_name() - new = imports.ImportWrapper(self, name).follow() + new = imports.infer_import(self, name) for module in new: if isinstance(module, ModuleContext): modules += module.star_imports()