forked from VimPlug/jedi
Move get_global_filters to the context module
This commit is contained in:
@@ -13,7 +13,7 @@ from jedi.api import keywords
|
|||||||
from jedi.api.file_name import file_name_completions
|
from jedi.api.file_name import file_name_completions
|
||||||
from jedi.inference import imports
|
from jedi.inference import imports
|
||||||
from jedi.inference.helpers import infer_call_of_leaf, parse_dotted_names
|
from jedi.inference.helpers import infer_call_of_leaf, parse_dotted_names
|
||||||
from jedi.inference.filters import get_global_filters
|
from jedi.inference.context import get_global_filters
|
||||||
from jedi.inference.gradual.conversion import convert_values
|
from jedi.inference.gradual.conversion import convert_values
|
||||||
from jedi.parser_utils import cut_value_at_position
|
from jedi.parser_utils import cut_value_at_position
|
||||||
|
|
||||||
@@ -222,14 +222,13 @@ class Completion:
|
|||||||
yield keywords.KeywordName(self._inference_state, k)
|
yield keywords.KeywordName(self._inference_state, k)
|
||||||
|
|
||||||
def _global_completions(self):
|
def _global_completions(self):
|
||||||
value = get_user_context(self._module_context, self._position)
|
context = get_user_context(self._module_context, self._position)
|
||||||
debug.dbg('global completion scope: %s', value)
|
debug.dbg('global completion scope: %s', context)
|
||||||
flow_scope_node = get_flow_scope_node(self._module_node, self._position)
|
flow_scope_node = get_flow_scope_node(self._module_node, self._position)
|
||||||
filters = get_global_filters(
|
filters = get_global_filters(
|
||||||
self._inference_state,
|
context,
|
||||||
value,
|
|
||||||
self._position,
|
self._position,
|
||||||
origin_scope=flow_scope_node
|
flow_scope_node
|
||||||
)
|
)
|
||||||
completion_names = []
|
completion_names = []
|
||||||
for filter in filters:
|
for filter in filters:
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
from abc import abstractmethod
|
from abc import abstractmethod
|
||||||
|
|
||||||
|
from parso.tree import search_ancestor
|
||||||
|
from parso.python.tree import Name
|
||||||
|
|
||||||
from jedi.inference.filters import ParserTreeFilter, MergedFilter, \
|
from jedi.inference.filters import ParserTreeFilter, MergedFilter, \
|
||||||
GlobalNameFilter
|
GlobalNameFilter
|
||||||
from jedi import parser_utils
|
from jedi import parser_utils
|
||||||
@@ -19,7 +22,9 @@ class AbstractContext(object):
|
|||||||
def goto(self, name_or_str, position):
|
def goto(self, name_or_str, position):
|
||||||
from jedi.inference import finder
|
from jedi.inference import finder
|
||||||
f = finder.NameFinder(self.inference_state, self, self, name_or_str, position)
|
f = finder.NameFinder(self.inference_state, self, self, name_or_str, position)
|
||||||
filters = f.get_global_filters()
|
filters = _get_global_filters_for_name(
|
||||||
|
self, name_or_str if isinstance(name_or_str, Name) else None, position,
|
||||||
|
)
|
||||||
return f.filter_name(filters)
|
return f.filter_name(filters)
|
||||||
|
|
||||||
def py__getattribute__(self, name_or_str, name_value=None, position=None,
|
def py__getattribute__(self, name_or_str, name_value=None, position=None,
|
||||||
@@ -32,7 +37,9 @@ class AbstractContext(object):
|
|||||||
from jedi.inference import finder
|
from jedi.inference import finder
|
||||||
f = finder.NameFinder(self.inference_state, self, name_value, name_or_str,
|
f = finder.NameFinder(self.inference_state, self, name_value, name_or_str,
|
||||||
position, analysis_errors=analysis_errors)
|
position, analysis_errors=analysis_errors)
|
||||||
filters = f.get_global_filters()
|
filters = _get_global_filters_for_name(
|
||||||
|
self, name_or_str if isinstance(name_or_str, Name) else None, position,
|
||||||
|
)
|
||||||
return f.find(filters, attribute_lookup=False)
|
return f.find(filters, attribute_lookup=False)
|
||||||
|
|
||||||
def get_root_context(self):
|
def get_root_context(self):
|
||||||
@@ -290,3 +297,90 @@ class CompiledContext(ValueContext):
|
|||||||
|
|
||||||
def py__file__(self):
|
def py__file__(self):
|
||||||
return self._value.py__file__()
|
return self._value.py__file__()
|
||||||
|
|
||||||
|
|
||||||
|
def _get_global_filters_for_name(context, name_or_none, position):
|
||||||
|
# For functions and classes the defaults don't belong to the
|
||||||
|
# function and get inferred in the value before the function. So
|
||||||
|
# make sure to exclude the function/class name.
|
||||||
|
if name_or_none is not None:
|
||||||
|
ancestor = search_ancestor(name_or_none, 'funcdef', 'classdef', 'lambdef')
|
||||||
|
lambdef = None
|
||||||
|
if ancestor == 'lambdef':
|
||||||
|
# For lambdas it's even more complicated since parts will
|
||||||
|
# be inferred later.
|
||||||
|
lambdef = ancestor
|
||||||
|
ancestor = search_ancestor(name_or_none, 'funcdef', 'classdef')
|
||||||
|
if ancestor is not None:
|
||||||
|
colon = ancestor.children[-2]
|
||||||
|
if position is not None and position < colon.start_pos:
|
||||||
|
if lambdef is None or position < lambdef.children[-2].start_pos:
|
||||||
|
position = ancestor.start_pos
|
||||||
|
|
||||||
|
return get_global_filters(context, position, name_or_none)
|
||||||
|
|
||||||
|
|
||||||
|
def get_global_filters(context, until_position, origin_scope):
|
||||||
|
"""
|
||||||
|
Returns all filters in order of priority for name resolution.
|
||||||
|
|
||||||
|
For global name lookups. The filters will handle name resolution
|
||||||
|
themselves, but here we gather possible filters downwards.
|
||||||
|
|
||||||
|
>>> from jedi._compatibility import u, no_unicode_pprint
|
||||||
|
>>> from jedi import Script
|
||||||
|
>>> script = Script(u('''
|
||||||
|
... x = ['a', 'b', 'c']
|
||||||
|
... def func():
|
||||||
|
... y = None
|
||||||
|
... '''))
|
||||||
|
>>> module_node = script._module_node
|
||||||
|
>>> scope = next(module_node.iter_funcdefs())
|
||||||
|
>>> scope
|
||||||
|
<Function: func@3-5>
|
||||||
|
>>> context = script._get_module_context().create_context(scope)
|
||||||
|
>>> filters = list(get_global_filters(context, (4, 0), None))
|
||||||
|
|
||||||
|
First we get the names from the function scope.
|
||||||
|
|
||||||
|
>>> no_unicode_pprint(filters[0]) # doctest: +ELLIPSIS
|
||||||
|
MergedFilter(<ParserTreeFilter: ...>, <GlobalNameFilter: ...>)
|
||||||
|
>>> sorted(str(n) for n in filters[0].values()) # doctest: +NORMALIZE_WHITESPACE
|
||||||
|
['<TreeNameDefinition: string_name=func start_pos=(3, 4)>',
|
||||||
|
'<TreeNameDefinition: string_name=x start_pos=(2, 0)>']
|
||||||
|
>>> filters[0]._filters[0]._until_position
|
||||||
|
(4, 0)
|
||||||
|
>>> filters[0]._filters[1]._until_position
|
||||||
|
|
||||||
|
Then it yields the names from one level "lower". In this example, this is
|
||||||
|
the module scope (including globals).
|
||||||
|
As a side note, you can see, that the position in the filter is None on the
|
||||||
|
globals filter, because there the whole module is searched.
|
||||||
|
|
||||||
|
>>> list(filters[1].values()) # package modules -> Also empty.
|
||||||
|
[]
|
||||||
|
>>> sorted(name.string_name for name in filters[2].values()) # Module attributes
|
||||||
|
['__doc__', '__name__', '__package__']
|
||||||
|
|
||||||
|
Finally, it yields the builtin filter, if `include_builtin` is
|
||||||
|
true (default).
|
||||||
|
|
||||||
|
>>> list(filters[3].values()) # doctest: +ELLIPSIS
|
||||||
|
[...]
|
||||||
|
"""
|
||||||
|
base_context = context
|
||||||
|
from jedi.inference.value.function import FunctionExecutionContext
|
||||||
|
while context is not None:
|
||||||
|
# Names in methods cannot be resolved within the class.
|
||||||
|
for filter in context.get_filters(
|
||||||
|
until_position=until_position,
|
||||||
|
origin_scope=origin_scope):
|
||||||
|
yield filter
|
||||||
|
if isinstance(context, FunctionExecutionContext):
|
||||||
|
# The position should be reset if the current scope is a function.
|
||||||
|
until_position = None
|
||||||
|
|
||||||
|
context = context.parent_context
|
||||||
|
|
||||||
|
# Add builtins to the global scope.
|
||||||
|
yield next(base_context.inference_state.builtins_module.get_filters())
|
||||||
|
|||||||
@@ -339,68 +339,3 @@ def publish_method(method_name, python_version_match=None):
|
|||||||
dct[method_name] = func, python_version_match
|
dct[method_name] = func, python_version_match
|
||||||
return func
|
return func
|
||||||
return decorator
|
return decorator
|
||||||
|
|
||||||
|
|
||||||
def get_global_filters(inference_state, context, until_position, origin_scope):
|
|
||||||
"""
|
|
||||||
Returns all filters in order of priority for name resolution.
|
|
||||||
|
|
||||||
For global name lookups. The filters will handle name resolution
|
|
||||||
themselves, but here we gather possible filters downwards.
|
|
||||||
|
|
||||||
>>> from jedi._compatibility import u, no_unicode_pprint
|
|
||||||
>>> from jedi import Script
|
|
||||||
>>> script = Script(u('''
|
|
||||||
... x = ['a', 'b', 'c']
|
|
||||||
... def func():
|
|
||||||
... y = None
|
|
||||||
... '''))
|
|
||||||
>>> module_node = script._module_node
|
|
||||||
>>> scope = next(module_node.iter_funcdefs())
|
|
||||||
>>> scope
|
|
||||||
<Function: func@3-5>
|
|
||||||
>>> context = script._get_module_context().create_context(scope)
|
|
||||||
>>> filters = list(get_global_filters(context.inference_state, context, (4, 0), None))
|
|
||||||
|
|
||||||
First we get the names from the function scope.
|
|
||||||
|
|
||||||
>>> no_unicode_pprint(filters[0]) # doctest: +ELLIPSIS
|
|
||||||
MergedFilter(<ParserTreeFilter: ...>, <GlobalNameFilter: ...>)
|
|
||||||
>>> sorted(str(n) for n in filters[0].values()) # doctest: +NORMALIZE_WHITESPACE
|
|
||||||
['<TreeNameDefinition: string_name=func start_pos=(3, 4)>',
|
|
||||||
'<TreeNameDefinition: string_name=x start_pos=(2, 0)>']
|
|
||||||
>>> filters[0]._filters[0]._until_position
|
|
||||||
(4, 0)
|
|
||||||
>>> filters[0]._filters[1]._until_position
|
|
||||||
|
|
||||||
Then it yields the names from one level "lower". In this example, this is
|
|
||||||
the module scope (including globals).
|
|
||||||
As a side note, you can see, that the position in the filter is None on the
|
|
||||||
globals filter, because there the whole module is searched.
|
|
||||||
|
|
||||||
>>> list(filters[1].values()) # package modules -> Also empty.
|
|
||||||
[]
|
|
||||||
>>> sorted(name.string_name for name in filters[2].values()) # Module attributes
|
|
||||||
['__doc__', '__name__', '__package__']
|
|
||||||
|
|
||||||
Finally, it yields the builtin filter, if `include_builtin` is
|
|
||||||
true (default).
|
|
||||||
|
|
||||||
>>> list(filters[3].values()) # doctest: +ELLIPSIS
|
|
||||||
[...]
|
|
||||||
"""
|
|
||||||
from jedi.inference.value.function import FunctionExecutionContext
|
|
||||||
while context is not None:
|
|
||||||
# Names in methods cannot be resolved within the class.
|
|
||||||
for filter in context.get_filters(
|
|
||||||
until_position=until_position,
|
|
||||||
origin_scope=origin_scope):
|
|
||||||
yield filter
|
|
||||||
if isinstance(context, FunctionExecutionContext):
|
|
||||||
# The position should be reset if the current scope is a function.
|
|
||||||
until_position = None
|
|
||||||
|
|
||||||
context = context.parent_context
|
|
||||||
|
|
||||||
# Add builtins to the global scope.
|
|
||||||
yield next(inference_state.builtins_module.get_filters())
|
|
||||||
|
|||||||
@@ -25,7 +25,6 @@ from jedi.inference import flow_analysis
|
|||||||
from jedi.inference.arguments import TreeArguments
|
from jedi.inference.arguments import TreeArguments
|
||||||
from jedi.inference import helpers
|
from jedi.inference import helpers
|
||||||
from jedi.inference.value import iterable
|
from jedi.inference.value import iterable
|
||||||
from jedi.inference.filters import get_global_filters
|
|
||||||
from jedi.inference.names import TreeNameDefinition
|
from jedi.inference.names import TreeNameDefinition
|
||||||
from jedi.inference.base_value import ValueSet, NO_VALUES
|
from jedi.inference.base_value import ValueSet, NO_VALUES
|
||||||
from jedi.parser_utils import is_scope, get_parent_scope
|
from jedi.parser_utils import is_scope, get_parent_scope
|
||||||
@@ -79,29 +78,6 @@ class NameFinder(object):
|
|||||||
|
|
||||||
return types
|
return types
|
||||||
|
|
||||||
def get_global_filters(self):
|
|
||||||
origin_scope = self._name if isinstance(self._name, tree.Name) else None
|
|
||||||
position = self._position
|
|
||||||
|
|
||||||
# For functions and classes the defaults don't belong to the
|
|
||||||
# function and get inferred in the value before the function. So
|
|
||||||
# make sure to exclude the function/class name.
|
|
||||||
if origin_scope is not None:
|
|
||||||
ancestor = search_ancestor(origin_scope, 'funcdef', 'classdef', 'lambdef')
|
|
||||||
lambdef = None
|
|
||||||
if ancestor == 'lambdef':
|
|
||||||
# For lambdas it's even more complicated since parts will
|
|
||||||
# be inferred later.
|
|
||||||
lambdef = ancestor
|
|
||||||
ancestor = search_ancestor(origin_scope, 'funcdef', 'classdef')
|
|
||||||
if ancestor is not None:
|
|
||||||
colon = ancestor.children[-2]
|
|
||||||
if position is not None and position < colon.start_pos:
|
|
||||||
if lambdef is None or position < lambdef.children[-2].start_pos:
|
|
||||||
position = ancestor.start_pos
|
|
||||||
|
|
||||||
return get_global_filters(self._inference_state, self._context, position, origin_scope)
|
|
||||||
|
|
||||||
def filter_name(self, filters):
|
def filter_name(self, filters):
|
||||||
"""
|
"""
|
||||||
Searches names that are defined in a scope (the different
|
Searches names that are defined in a scope (the different
|
||||||
|
|||||||
Reference in New Issue
Block a user