diff --git a/jedi/evaluate/finder.py b/jedi/evaluate/finder.py index cec7b785..6557c7d9 100644 --- a/jedi/evaluate/finder.py +++ b/jedi/evaluate/finder.py @@ -478,12 +478,18 @@ def get_names_of_scope(evaluator, scope, position=None, star_search=True, includ is the most outer scope. >>> pairs[1] - (, [, ]) + (>, [, ]) + + After that we have a few underscore names that have been defined + + >>> pairs[2] + (>, [, ...]) + Finally, it yields names from builtin, if `include_builtin` is true (default). - >>> pairs[2] #doctest: +ELLIPSIS + >>> pairs[3] #doctest: +ELLIPSIS (, [, ...]) :rtype: [(pr.Scope, [pr.Name])] @@ -510,13 +516,15 @@ def get_names_of_scope(evaluator, scope, position=None, star_search=True, includ or isinstance(scope, compiled.CompiledObject) and scope.type() == 'class' and in_func_scope != scope): try: - if isinstance(scope, er.Instance): - for g in scope.scope_names_generator(): - yield g - else: - if isinstance(scope, (pr.SubModule, fast.Module)): - scope = er.ModuleWrapper(evaluator, scope) + if isinstance(scope, (pr.SubModule, fast.Module)): + scope = er.ModuleWrapper(evaluator, scope) + try: + sng = scope.scope_names_generator + except AttributeError: yield scope, _get_defined_names_for_position(scope, position, in_func_scope) + else: + for g in sng(position): + yield g except StopIteration: reraise(common.MultiLevelStopIteration, sys.exc_info()[2]) if scope.isinstance(pr.ListComprehension): @@ -528,6 +536,9 @@ def get_names_of_scope(evaluator, scope, position=None, star_search=True, includ # results. if scope and scope.isinstance(er.Function, pr.Function, er.FunctionExecution): in_func_scope = scope + if in_func_scope != scope \ + and isinstance(in_func_scope, (pr.Function, er.FunctionExecution)): + position = None # Add star imports. if star_search: diff --git a/jedi/evaluate/imports.py b/jedi/evaluate/imports.py index 6f93f2e0..8660782b 100644 --- a/jedi/evaluate/imports.py +++ b/jedi/evaluate/imports.py @@ -250,8 +250,8 @@ class StarImportModule(pr.Module): self._module = module self.star_import_modules = star_import_modules - def scope_names_generator(self): - for module, names in self._module.scope_names_generator(): + def scope_names_generator(self, position=None): + for module, names in self._module.scope_names_generator(position): yield module, names for s in self.star_import_modules: yield s, s.get_defined_names() diff --git a/jedi/evaluate/representation.py b/jedi/evaluate/representation.py index e2a2c5b9..f25982b4 100644 --- a/jedi/evaluate/representation.py +++ b/jedi/evaluate/representation.py @@ -151,7 +151,7 @@ class Instance(use_metaclass(CachedMetaClass, Executable)): names.append(InstanceElement(self._evaluator, self, var, True)) return names - def scope_names_generator(self): + def scope_names_generator(self, position=None): """ An Instance has two scopes: The scope with self names and the class scope. Instance variables have priority over the class scope. @@ -540,17 +540,19 @@ class ModuleWrapper(use_metaclass(CachedMetaClass, pr.Module)): self._evaluator = evaluator self._module = module - def scope_names_generator(self): - yield self, self.get_defined_names() - yield self, self._sub_modules() + def scope_names_generator(self, position=None): + yield self, filter_after_position(self.get_defined_names(), position) + yield self, self.module_attributes() + sub_modules = self._sub_modules() + if sub_modules: + yield self, self._sub_modules() @memoize_default() - def get_defined_names(self): + def module_attributes(self): names = ['__file__', '__package__', '__doc__', '__name__', '__version__'] # All the additional module attributes are strings. parent = Instance(self._evaluator, compiled.create(self._evaluator, str)) - module_attributes = [helpers.FakeName(n, parent) for n in names] - return self._module.get_defined_names() + module_attributes + return [helpers.FakeName(n, parent) for n in names] @memoize_default() def _sub_modules(self): @@ -560,7 +562,7 @@ class ModuleWrapper(use_metaclass(CachedMetaClass, pr.Module)): """ path = self._module.path names = [] - if path.endswith(os.path.sep + '__init__.py'): + if path is not None and path.endswith(os.path.sep + '__init__.py'): mods = pkgutil.iter_modules([os.path.dirname(path)]) for module_loader, name, is_pkg in mods: name = helpers.FakeName(name) @@ -575,3 +577,14 @@ class ModuleWrapper(use_metaclass(CachedMetaClass, pr.Module)): def __repr__(self): return "<%s: %s>" % (type(self).__name__, self._module) + + +def filter_after_position(names, position): + if position is None: + return names + + names_new = [] + for n in names: + if n.start_pos[0] is not None and n.start_pos < position: + names_new.append(n) + return names_new