diff --git a/jedi/api/__init__.py b/jedi/api/__init__.py index e075cfc7..c571863b 100644 --- a/jedi/api/__init__.py +++ b/jedi/api/__init__.py @@ -217,7 +217,7 @@ class Script(object): for name in names: definition = name.get_definition() if definition.type in ('import_name', 'import_from'): - imp = imports.ImportWrapper(self._evaluator, name) + imp = imports.ImportWrapper(context, name) for name in filter_follow_imports(imp.follow(is_goto=True)): yield name else: @@ -340,7 +340,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(self._evaluator, n).follow() + imports.ImportWrapper(context, n).follow() elif node.type == 'expr_stmt': types = self._evaluator.eval_element(node) for testlist in node.children[:-1:2]: diff --git a/jedi/api/classes.py b/jedi/api/classes.py index 8c1e0f25..fff755c1 100644 --- a/jedi/api/classes.py +++ b/jedi/api/classes.py @@ -170,7 +170,9 @@ class BaseDefinition(object): par = self._definition while par is not None: if isinstance(par, tree.Import): - path += imports.ImportWrapper(self._evaluator, self._name).import_path + # Not self._name.infer()? + raise DeprecationWarning + path += imports.ImportWrapper(self._name.context, self._name).import_path break try: name = par.name @@ -323,6 +325,8 @@ class BaseDefinition(object): if self._definition.isinstance(tree.ExprStmt): return self._evaluator.eval_statement(self._definition) elif self._definition.isinstance(tree.Import): + raise DeprecationWarning + # TODO self._name.infer()? return imports.ImportWrapper(self._evaluator, self._name).follow() else: return set([self._definition]) @@ -475,6 +479,7 @@ class Completion(BaseDefinition): """ definition = self._definition if isinstance(definition, tree.Import): + raise DeprecationWarning i = imports.ImportWrapper(self._evaluator, self._name) if len(i.import_path) > 1 or not fast: followed = self._follow_statements_imports() @@ -494,6 +499,7 @@ class Completion(BaseDefinition): description, look at :attr:`jedi.api.classes.BaseDefinition.type`. """ if isinstance(self._definition, tree.Import): + raise DeprecationWarning i = imports.ImportWrapper(self._evaluator, self._name) if len(i.import_path) <= 1: return 'module' @@ -514,6 +520,7 @@ class Completion(BaseDefinition): # TODO REMOVE definition = self._definition if definition.isinstance(tree.Import): + raise DeprecationWarning i = imports.ImportWrapper(self._evaluator, self._name) return i.follow() return super(Completion, self)._follow_statements_imports() diff --git a/jedi/api/usages.py b/jedi/api/usages.py index ecb88563..3907ccb6 100644 --- a/jedi/api/usages.py +++ b/jedi/api/usages.py @@ -44,6 +44,6 @@ def usages_add_import_modules(evaluator, definitions): for d in definitions: imp_or_stmt = d.get_definition() if isinstance(imp_or_stmt, tree.Import): - s = imports.ImportWrapper(evaluator, d) + s = imports.ImportWrapper(context, d) new |= set(s.follow(is_goto=True)) return set(definitions) | new diff --git a/jedi/evaluate/__init__.py b/jedi/evaluate/__init__.py index 876f642a..a6aa6d34 100644 --- a/jedi/evaluate/__init__.py +++ b/jedi/evaluate/__init__.py @@ -427,7 +427,7 @@ 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(self, name).follow() + return imports.ImportWrapper(context, name).follow() call = helpers.call_of_leaf(name) return self.eval_element(context, call) @@ -437,7 +437,7 @@ class Evaluator(object): for name in names: if isinstance(name.parent, helpers.FakeImport): # Those are implicit imports. - s = imports.ImportWrapper(self, name) + s = imports.ImportWrapper(context, name) for n in s.follow(is_goto=True): yield n else: @@ -476,7 +476,7 @@ class Evaluator(object): elif isinstance(par, (tree.Param, tree.Function, tree.Class)) and par.name is name: return [name] elif isinstance(stmt, tree.Import): - modules = imports.ImportWrapper(self, name).follow(is_goto=True) + modules = imports.ImportWrapper(context, name).follow(is_goto=True) return list(resolve_implicit_imports(modules)) elif par.type == 'dotted_name': # Is a decorator. index = par.children.index(name) diff --git a/jedi/evaluate/context.py b/jedi/evaluate/context.py index be6c83ec..b30bd596 100644 --- a/jedi/evaluate/context.py +++ b/jedi/evaluate/context.py @@ -32,6 +32,9 @@ class Context(object): def eval_node(self, node): return self.evaluator.eval_element(self, node) + def eval_stmt(self, stmt, seek_name=None): + return self.evaluator.eval_statement(self, stmt, seek_name) + class TreeContext(Context): pass diff --git a/jedi/evaluate/dynamic.py b/jedi/evaluate/dynamic.py index 28544539..500deab9 100644 --- a/jedi/evaluate/dynamic.py +++ b/jedi/evaluate/dynamic.py @@ -71,7 +71,6 @@ def search_params(evaluator, parent_context, funcdef): if not settings.dynamic_params: return set() - raise NotImplementedError evaluator.dynamic_params_depth += 1 try: debug.dbg('Dynamic param search in %s.', funcdef.name.value, color='MAGENTA') @@ -137,7 +136,8 @@ def _search_function_executions(evaluator, funcdef): random_context = evaluator.create_context(module_context, name) for value in evaluator.goto_definitions(random_context, name): - if compare_node == value.funcdef: + value_node = value.get_node() + if compare_node == value_node: arglist = trailer.children[1] if arglist == ')': arglist = () @@ -145,7 +145,7 @@ def _search_function_executions(evaluator, funcdef): yield er.FunctionExecutionContext( evaluator, value.parent_context, - value.funcdef, + value_node, args ) found_executions = True diff --git a/jedi/evaluate/finder.py b/jedi/evaluate/finder.py index 94fc41de..1ccfe768 100644 --- a/jedi/evaluate/finder.py +++ b/jedi/evaluate/finder.py @@ -372,7 +372,7 @@ def _name_to_types(evaluator, context, name, scope): elif node.isinstance(tree.WithStmt): types = evaluator.eval_element(node.node_from_name(name)) elif isinstance(node, tree.Import): - types = imports.ImportWrapper(evaluator, name).follow() + types = imports.ImportWrapper(context, name).follow() elif node.type in ('funcdef', 'classdef'): types = _apply_decorators(evaluator, context, node) elif node.type == 'global_stmt': @@ -459,7 +459,7 @@ def _remove_statements(evaluator, context, stmt, name): pep0484.find_type_from_comment_hint_assign(evaluator, stmt, name) if pep0484types: return pep0484types - types |= evaluator.eval_statement(context, stmt, seek_name=name) + types |= context.eval_stmt(stmt, seek_name=name) if check_instance is not None: # class renames @@ -666,19 +666,21 @@ def check_tuple_assignments(evaluator, types, name): """ Checks if tuples are assigned. """ + lazy_context = None for index, node in name.assignment_indexes(): iterated = iterable.py__iter__(evaluator, types, node) for _ in range(index + 1): try: - types = next(iterated) + lazy_context = next(iterated) except StopIteration: # We could do this with the default param in next. But this # would allow this loop to run for a very long time if the # index number is high. Therefore break if the loop is # finished. - types = set() - break - return types + return set() + if lazy_context is None: + return types + return lazy_context.infer() def filter_private_variable(scope, origin_node): diff --git a/jedi/evaluate/imports.py b/jedi/evaluate/imports.py index 50247c6f..d6088a08 100644 --- a/jedi/evaluate/imports.py +++ b/jedi/evaluate/imports.py @@ -29,7 +29,6 @@ from jedi import settings from jedi.common import source_to_unicode from jedi.evaluate import compiled from jedi.evaluate import analysis -from jedi.evaluate.cache import memoize_default, NO_DEFAULT def completion_names(evaluator, imp, pos): @@ -58,17 +57,17 @@ def completion_names(evaluator, imp, pos): return importer.completion_names(evaluator, only_modules) -class ImportWrapper(tree.Base): - def __init__(self, evaluator, name): - self._evaluator = evaluator +class ImportWrapper(object): + def __init__(self, context, name): + self._context = context self._name = name self._import = name.get_parent_until(tree.Import) self.import_path = self._import.path_for_name(name) - @memoize_default() + # TODO move this whole thing to a function def follow(self, is_goto=False): - module = self._evaluator.wrap(self._import.get_parent_until()) + module = self._import.get_parent_until() import_path = self._import.path_for_name(self._name) from_import_name = None try: @@ -83,7 +82,7 @@ class ImportWrapper(tree.Base): from_import_name = import_path[-1] import_path = from_names - importer = Importer(self._evaluator, tuple(import_path), + importer = Importer(self._context.evaluator, tuple(import_path), module, self._import.level) types = importer.follow() @@ -93,13 +92,13 @@ class ImportWrapper(tree.Base): if from_import_name is not None: types = set(chain.from_iterable( - self._evaluator.find_types(t, unicode(from_import_name), + self.evaluator.find_types(t, unicode(from_import_name), is_goto=is_goto) for t in types)) if not types: path = import_path + [from_import_name] - importer = Importer(self._evaluator, tuple(path), + importer = Importer(self.evaluator, tuple(path), module, self._import.level) types = importer.follow() # goto only accepts `Name` @@ -219,7 +218,6 @@ class Importer(object): """Returns the import path as pure strings instead of `Name`.""" return tuple(str(name) for name in self.import_path) - @memoize_default() def sys_path_with_modifications(self): in_path = [] sys_path_mod = list(sys_path.sys_path_with_modifications(self._evaluator, self.module)) @@ -239,7 +237,6 @@ class Importer(object): return in_path + sys_path_mod - @memoize_default(NO_DEFAULT) def follow(self): if not self.import_path: return set() @@ -513,4 +510,5 @@ def get_module_nodes_containing_name(evaluator, module_nodes, name): # make testing easier, sort it - same results on every interpreter c = check_python_file(p) if c is not None and c not in module_nodes and not isinstance(c, compiled.CompiledObject): + continue # TODO REENABLE yield c.module_node diff --git a/jedi/evaluate/representation.py b/jedi/evaluate/representation.py index 7280ea44..6194c032 100644 --- a/jedi/evaluate/representation.py +++ b/jedi/evaluate/representation.py @@ -415,6 +415,9 @@ class ClassContext(use_metaclass(CachedMetaClass, context.TreeContext, Wrapper)) super(ClassContext, self).__init__(evaluator, parent_context=parent_context) self.classdef = classdef + def get_node(self): + return self.classdef + @memoize_default(default=()) def py__mro__(self): def add(cls): @@ -523,6 +526,9 @@ class FunctionContext(use_metaclass(CachedMetaClass, context.TreeContext, Wrappe super(FunctionContext, self).__init__(evaluator, parent_context) self.base = self.base_func = self.funcdef = funcdef + def get_node(self): + return self.funcdef + def names_dicts(self, search_global): if search_global: yield self.names_dict @@ -788,7 +794,7 @@ class ModuleContext(use_metaclass(CachedMetaClass, context.TreeContext, Wrapper) for i in self.module_node.imports: if i.is_star_import(): name = i.star_import_name() - new = imports.ImportWrapper(self.evaluator, name).follow() + new = imports.ImportWrapper(self, name).follow() for module in new: if isinstance(module, tree.Module): modules += module.star_imports()