forked from VimPlug/jedi
moved get_names_for_scope to finder
This commit is contained in:
@@ -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:
|
||||||
|
|||||||
@@ -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)]
|
||||||
|
|
||||||
|
|||||||
@@ -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):
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
Reference in New Issue
Block a user