1
0
forked from VimPlug/jedi

moved get_names_for_scope to finder

This commit is contained in:
Dave Halter
2014-01-17 11:33:46 +01:00
parent de6a6b5813
commit 97ad1c6a29
5 changed files with 102 additions and 96 deletions

View File

@@ -29,6 +29,7 @@ from jedi.evaluate import representation as er
from jedi.evaluate import compiled from jedi.evaluate import compiled
from jedi.evaluate import imports from jedi.evaluate import imports
from jedi.evaluate import helpers from jedi.evaluate import helpers
from jedi.evaluate.finder import get_names_of_scope
class NotFoundError(Exception): class NotFoundError(Exception):
@@ -170,8 +171,9 @@ class Script(object):
scopes = list(self._prepare_goto(path, True)) scopes = list(self._prepare_goto(path, True))
except NotFoundError: except NotFoundError:
scopes = [] scopes = []
scope_generator = self._evaluator.get_names_of_scope( scope_generator = get_names_of_scope(self._evaluator,
self._parser.user_scope(), self._pos) self._parser.user_scope(),
self._pos)
completions = [] completions = []
for scope, name_list in scope_generator: for scope, name_list in scope_generator:
for c in name_list: for c in name_list:

View File

@@ -16,6 +16,7 @@ from jedi.evaluate import iterable
from jedi.evaluate import imports from jedi.evaluate import imports
from jedi.evaluate import compiled from jedi.evaluate import compiled
from jedi.api import keywords from jedi.api import keywords
from jedi.evaluate.finder import get_names_of_scope
def clear_caches(): def clear_caches():
@@ -550,8 +551,8 @@ def defined_names(evaluator, scope):
:type scope: Scope :type scope: Scope
:rtype: list of Definition :rtype: list of Definition
""" """
pair = next(evaluator.get_names_of_scope( pair = next(get_names_of_scope(evaluator, scope, star_search=False,
scope, star_search=False, include_builtin=False), None) include_builtin=False), None)
names = pair[1] if pair else [] names = pair[1] if pair else []
return [Definition(evaluator, d) for d in sorted(names, key=lambda s: s.start_pos)] return [Definition(evaluator, d) for d in sorted(names, key=lambda s: s.start_pos)]

View File

@@ -68,10 +68,9 @@ backtracking algorithm.
.. todo:: nonlocal statement, needed or can be ignored? (py3k) .. todo:: nonlocal statement, needed or can be ignored? (py3k)
""" """
import sys
import itertools import itertools
from jedi._compatibility import next, hasattr, unicode, reraise from jedi._compatibility import next, hasattr, unicode
from jedi import common from jedi import common
from jedi.parser import representation as pr from jedi.parser import representation as pr
from jedi import debug from jedi import debug
@@ -91,92 +90,6 @@ class Evaluator(object):
self.recursion_detector = recursion.RecursionDetector() self.recursion_detector = recursion.RecursionDetector()
self.execution_recursion_detector = recursion.ExecutionRecursionDetector() self.execution_recursion_detector = recursion.ExecutionRecursionDetector()
def get_names_of_scope(self, scope, position=None, star_search=True,
include_builtin=True):
"""
Get all completions (names) possible for the current scope.
The star search option is only here to provide an optimization. Otherwise
the whole thing would probably start a little recursive madness.
This function is used to include names from outer scopes. For example,
when the current scope is function:
>>> from jedi.parser import Parser
>>> parser = Parser('''
... x = ['a', 'b', 'c']
... def func():
... y = None
... ''')
>>> scope = parser.module.subscopes[0]
>>> scope
<Function: func@3-4>
`get_names_of_scope` is a generator. First it yields names from
most inner scope.
>>> pairs = list(Evaluator().get_names_of_scope(scope))
>>> pairs[0]
(<Function: func@3-4>, [<Name: y@4,4>])
Then it yield the names from one level outer scope. For this
example, this is the most outer scope.
>>> pairs[1]
(<SubModule: None@1-4>, [<Name: x@2,0>, <Name: func@3,4>])
Finally, it yields names from builtin, if `include_builtin` is
true (default).
>>> pairs[2] #doctest: +ELLIPSIS
(<Builtin: ...builtin...>, [<CompiledName: ...>, ...])
:rtype: [(pr.Scope, [pr.Name])]
:return: Return an generator that yields a pair of scope and names.
"""
in_func_scope = scope
non_flow = scope.get_parent_until(pr.Flow, reverse=True)
while scope:
if isinstance(scope, pr.SubModule) and scope.parent:
# we don't want submodules to report if we have modules.
scope = scope.parent
continue
# `pr.Class` is used, because the parent is never `Class`.
# Ignore the Flows, because the classes and functions care for that.
# InstanceElement of Class is ignored, if it is not the start scope.
if not (scope != non_flow and scope.isinstance(pr.Class)
or scope.isinstance(pr.Flow)
or scope.isinstance(er.Instance)
and non_flow.isinstance(er.Function)
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_generator():
yield g
else:
yield scope, finder._get_defined_names_for_position(scope, position, in_func_scope)
except StopIteration:
reraise(common.MultiLevelStopIteration, sys.exc_info()[2])
if scope.isinstance(pr.ForFlow) and scope.is_list_comp:
# is a list comprehension
yield scope, scope.get_set_vars(is_internal_call=True)
scope = scope.parent
# This is used, because subscopes (Flow scopes) would distort the
# results.
if scope and scope.isinstance(er.Function, pr.Function, er.FunctionExecution):
in_func_scope = scope
# Add star imports.
if star_search:
for s in imports.remove_star_imports(self, non_flow.get_parent_until()):
for g in self.get_names_of_scope(s, star_search=False):
yield g
# Add builtins to the global scope.
if include_builtin:
yield compiled.builtin, compiled.builtin.get_defined_names()
def find_types(self, scope, name_str, position=None, search_global=False, def find_types(self, scope, name_str, position=None, search_global=False,
is_goto=False, resolve_decorator=True): is_goto=False, resolve_decorator=True):
""" """

View File

@@ -1,6 +1,7 @@
import copy import copy
import sys
from jedi._compatibility import hasattr, unicode, u from jedi._compatibility import hasattr, unicode, u, reraise
from jedi.parser import representation as pr from jedi.parser import representation as pr
from jedi import debug from jedi import debug
from jedi import common from jedi import common
@@ -10,6 +11,7 @@ from jedi.evaluate import dynamic
from jedi.evaluate import compiled from jedi.evaluate import compiled
from jedi.evaluate import docstrings from jedi.evaluate import docstrings
from jedi.evaluate import iterable from jedi.evaluate import iterable
from jedi.evaluate import imports
class NameFinder(object): class NameFinder(object):
@@ -27,7 +29,7 @@ class NameFinder(object):
def scopes(self, search_global=False): def scopes(self, search_global=False):
if search_global: if search_global:
return self._evaluator.get_names_of_scope(self.scope, self.position) return get_names_of_scope(self._evaluator, self.scope, self.position)
else: else:
if isinstance(self.scope, er.Instance): if isinstance(self.scope, er.Instance):
return self.scope.scope_generator() return self.scope.scope_generator()
@@ -361,6 +363,93 @@ def _get_defined_names_for_position(scope, position=None, start_scope=None):
return names_new return names_new
def get_names_of_scope(evaluator, scope, position=None, star_search=True, include_builtin=True):
"""
Get all completions (names) possible for the current scope. The star search
option is only here to provide an optimization. Otherwise the whole thing
would probably start a little recursive madness.
This function is used to include names from outer scopes. For example, when
the current scope is function:
>>> from jedi.parser import Parser
>>> parser = Parser('''
... x = ['a', 'b', 'c']
... def func():
... y = None
... ''')
>>> scope = parser.module.subscopes[0]
>>> scope
<Function: func@3-4>
`get_names_of_scope` is a generator. First it yields names from most inner
scope.
>>> from jedi.evaluate import Evaluator
>>> pairs = list(get_names_of_scope(Evaluator(), scope))
>>> pairs[0]
(<Function: func@3-4>, [<Name: y@4,4>])
Then it yield the names from one level outer scope. For this example, this
is the most outer scope.
>>> pairs[1]
(<SubModule: None@1-4>, [<Name: x@2,0>, <Name: func@3,4>])
Finally, it yields names from builtin, if `include_builtin` is
true (default).
>>> pairs[2] #doctest: +ELLIPSIS
(<Builtin: ...builtin...>, [<CompiledName: ...>, ...])
:rtype: [(pr.Scope, [pr.Name])]
:return: Return an generator that yields a pair of scope and names.
"""
in_func_scope = scope
non_flow = scope.get_parent_until(pr.Flow, reverse=True)
while scope:
if isinstance(scope, pr.SubModule) and scope.parent:
# we don't want submodules to report if we have modules.
scope = scope.parent
continue
# `pr.Class` is used, because the parent is never `Class`.
# Ignore the Flows, because the classes and functions care for that.
# InstanceElement of Class is ignored, if it is not the start scope.
if not (scope != non_flow and scope.isinstance(pr.Class)
or scope.isinstance(pr.Flow)
or scope.isinstance(er.Instance)
and non_flow.isinstance(er.Function)
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_generator():
yield g
else:
yield scope, _get_defined_names_for_position(scope, position, in_func_scope)
except StopIteration:
reraise(common.MultiLevelStopIteration, sys.exc_info()[2])
if scope.isinstance(pr.ForFlow) and scope.is_list_comp:
# is a list comprehension
yield scope, scope.get_set_vars(is_internal_call=True)
scope = scope.parent
# This is used, because subscopes (Flow scopes) would distort the
# results.
if scope and scope.isinstance(er.Function, pr.Function, er.FunctionExecution):
in_func_scope = scope
# Add star imports.
if star_search:
for s in imports.remove_star_imports(evaluator, non_flow.get_parent_until()):
for g in get_names_of_scope(evaluator, s, star_search=False):
yield g
# Add builtins to the global scope.
if include_builtin:
yield compiled.builtin, compiled.builtin.get_defined_names()
def _assign_tuples(tup, results, seek_name): def _assign_tuples(tup, results, seek_name):
""" """
This is a normal assignment checker. In python functions and other things This is a normal assignment checker. In python functions and other things

View File

@@ -131,8 +131,9 @@ class ImportPath(pr.Base):
names.append(pr.Name(self.GlobalNamespace, [('path', p)], names.append(pr.Name(self.GlobalNamespace, [('path', p)],
p, p, self.import_stmt)) p, p, self.import_stmt))
continue continue
for s, scope_names in self._evaluator.get_names_of_scope(scope, from jedi.evaluate import finder
include_builtin=False): for s, scope_names in finder.get_names_of_scope(self._evaluator,
scope, include_builtin=False):
for n in scope_names: for n in scope_names:
if self.import_stmt.from_ns is None \ if self.import_stmt.from_ns is None \
or self.is_partial_import: or self.is_partial_import: