diff --git a/jedi/api/interpreter.py b/jedi/api/interpreter.py index e1b909ef..318dc7a7 100644 --- a/jedi/api/interpreter.py +++ b/jedi/api/interpreter.py @@ -18,12 +18,16 @@ class InterpreterNamespace(pr.Module): self.parser_module = parser_module self._evaluator = evaluator + @underscore_memoization def get_defined_names(self): for name in self.parser_module.get_defined_names(): yield name for key, value in self.namespace.items(): yield LazyName(self._evaluator, key, value) + def scope_names_generator(self, position=None): + yield self, list(self.get_defined_names()) + def __getattr__(self, name): return getattr(self.parser_module, name) diff --git a/jedi/evaluate/compiled/__init__.py b/jedi/evaluate/compiled/__init__.py index 2f8be3a9..062f14a8 100644 --- a/jedi/evaluate/compiled/__init__.py +++ b/jedi/evaluate/compiled/__init__.py @@ -88,6 +88,9 @@ class CompiledObject(Base): else: return type_names + self.instance_names() + def scope_names_generator(self, position=None): + yield self, self.get_defined_names() + @underscore_memoization def instance_names(self): names = [] diff --git a/jedi/evaluate/finder.py b/jedi/evaluate/finder.py index 6557c7d9..2b52cc13 100644 --- a/jedi/evaluate/finder.py +++ b/jedi/evaluate/finder.py @@ -435,9 +435,7 @@ def _get_defined_names_for_position(scope, position=None, start_scope=None): names = scope.get_defined_names() # Instances have special rules, always return all the possible completions, # because class variables are always valid and the `self.` variables, too. - if not position or isinstance(scope, (iterable.Array, er.Instance, compiled.CompiledObject)) \ - or start_scope != scope \ - and isinstance(start_scope, (pr.Function, er.FunctionExecution)): + if not position or isinstance(scope, (iterable.Array, er.Instance, compiled.CompiledObject)): return names names_new = [] for n in names: @@ -518,6 +516,10 @@ def get_names_of_scope(evaluator, scope, position=None, star_search=True, includ try: if isinstance(scope, (pr.SubModule, fast.Module)): scope = er.ModuleWrapper(evaluator, scope) + + for g in scope.scope_names_generator(position): + yield g + """ try: sng = scope.scope_names_generator except AttributeError: @@ -525,6 +527,7 @@ def get_names_of_scope(evaluator, scope, position=None, star_search=True, includ else: for g in sng(position): yield g + """ except StopIteration: reraise(common.MultiLevelStopIteration, sys.exc_info()[2]) if scope.isinstance(pr.ListComprehension): diff --git a/jedi/evaluate/representation.py b/jedi/evaluate/representation.py index f25982b4..ea1eb6d3 100644 --- a/jedi/evaluate/representation.py +++ b/jedi/evaluate/representation.py @@ -315,6 +315,10 @@ class Class(use_metaclass(CachedMetaClass, pr.IsScope)): type_cls = self._evaluator.find_types(compiled.builtin, 'type')[0] return result + list(type_cls.get_defined_names()) + def scope_names_generator(self, position=None): + yield self, self.instance_names() + yield self, compiled.type_names + def get_subscope_by_name(self, name): for s in [self] + self.get_super_classes(): for sub in reversed(s.subscopes): @@ -468,6 +472,10 @@ class FunctionExecution(Executable): """ return self._get_params() + pr.Scope.get_defined_names(self) + def scope_names_generator(self, position=None): + names = pr.filter_after_position(pr.Scope.get_defined_names(self), position) + yield self, self._get_params() + names + def _copy_properties(self, prop): """ Literally copies a property of a Function. Copying is very expensive, @@ -541,7 +549,7 @@ class ModuleWrapper(use_metaclass(CachedMetaClass, pr.Module)): self._module = module def scope_names_generator(self, position=None): - yield self, filter_after_position(self.get_defined_names(), position) + yield self, pr.filter_after_position(self.get_defined_names(), position) yield self, self.module_attributes() sub_modules = self._sub_modules() if sub_modules: @@ -577,14 +585,3 @@ 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 diff --git a/jedi/parser/representation.py b/jedi/parser/representation.py index 3572c445..192ee35d 100644 --- a/jedi/parser/representation.py +++ b/jedi/parser/representation.py @@ -49,6 +49,17 @@ from jedi.parser import tokenize SCOPE_CONTENTS = 'asserts', 'subscopes', 'imports', 'statements', 'returns' +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 + + class GetCodeState(object): """A helper class for passing the state of get_code in a thread-safe manner.""" @@ -499,6 +510,9 @@ class Class(Scope): sub.get_call_signature(funcname=self.name.names[-1]), docstr) return docstr + def scope_names_generator(self, position=None): + yield self, filter_after_position(self.get_defined_names(), position) + class Function(Scope): """ @@ -545,6 +559,9 @@ class Function(Scope): debug.warning("multiple names in param %s", n) return n + def scope_names_generator(self, position=None): + yield self, filter_after_position(self.get_defined_names(), position) + def get_call_signature(self, width=72, funcname=None): """ Generate call signature of this function.