forked from VimPlug/jedi
Filters for compiled objects and also FunctionExecution.
This commit is contained in:
@@ -12,6 +12,7 @@ from jedi import debug
|
|||||||
from jedi.cache import underscore_memoization, memoize_method
|
from jedi.cache import underscore_memoization, memoize_method
|
||||||
from jedi.parser.tree import Param, Base, Operator
|
from jedi.parser.tree import Param, Base, Operator
|
||||||
from jedi.evaluate.helpers import FakeName
|
from jedi.evaluate.helpers import FakeName
|
||||||
|
from jedi.evaluate.filters import AbstractFilter
|
||||||
from . import fake
|
from . import fake
|
||||||
|
|
||||||
|
|
||||||
@@ -156,6 +157,9 @@ class CompiledObject(Base):
|
|||||||
def names_dicts(self, search_global, is_instance=False):
|
def names_dicts(self, search_global, is_instance=False):
|
||||||
return self._names_dict_ensure_one_dict(is_instance)
|
return self._names_dict_ensure_one_dict(is_instance)
|
||||||
|
|
||||||
|
def get_filters(self, search_global, is_instance=False):
|
||||||
|
yield self._ensure_one_filter(is_instance)
|
||||||
|
|
||||||
@memoize_method
|
@memoize_method
|
||||||
def _names_dict_ensure_one_dict(self, is_instance):
|
def _names_dict_ensure_one_dict(self, is_instance):
|
||||||
"""
|
"""
|
||||||
@@ -164,6 +168,14 @@ class CompiledObject(Base):
|
|||||||
"""
|
"""
|
||||||
return [LazyNamesDict(self._evaluator, self, is_instance)]
|
return [LazyNamesDict(self._evaluator, self, is_instance)]
|
||||||
|
|
||||||
|
@memoize_method
|
||||||
|
def _ensure_one_filter(self, is_instance):
|
||||||
|
"""
|
||||||
|
search_global shouldn't change the fact that there's one dict, this way
|
||||||
|
there's only one `object`.
|
||||||
|
"""
|
||||||
|
return CompiledObjectFilter(self._evaluator, self, is_instance)
|
||||||
|
|
||||||
def get_subscope_by_name(self, name):
|
def get_subscope_by_name(self, name):
|
||||||
if name in dir(self.obj):
|
if name in dir(self.obj):
|
||||||
return CompiledName(self._evaluator, self, name).parent
|
return CompiledName(self._evaluator, self, name).parent
|
||||||
@@ -314,6 +326,50 @@ class LazyNamesDict(object):
|
|||||||
return values
|
return values
|
||||||
|
|
||||||
|
|
||||||
|
class CompiledObjectFilter(AbstractFilter):
|
||||||
|
"""
|
||||||
|
A names_dict instance for compiled objects, resembles the parser.tree.
|
||||||
|
"""
|
||||||
|
name_class = CompiledName
|
||||||
|
|
||||||
|
def __init__(self, evaluator, compiled_obj, is_instance=False):
|
||||||
|
self._evaluator = evaluator
|
||||||
|
self._compiled_obj = compiled_obj
|
||||||
|
self._is_instance = is_instance
|
||||||
|
|
||||||
|
@memoize_method
|
||||||
|
def get(self, name, until_position=None):
|
||||||
|
name = str(name)
|
||||||
|
try:
|
||||||
|
getattr(self._compiled_obj.obj, name)
|
||||||
|
except AttributeError:
|
||||||
|
return []
|
||||||
|
except Exception:
|
||||||
|
# This is a bit ugly. We're basically returning this to make
|
||||||
|
# lookups possible without having the actual attribute. However
|
||||||
|
# this makes proper completion possible.
|
||||||
|
return [FakeName(name, create(self._evaluator, None), is_definition=True)]
|
||||||
|
return [self.name_class(self._evaluator, self._compiled_obj, name)]
|
||||||
|
|
||||||
|
def values(self, until_position=None):
|
||||||
|
raise NotImplementedError
|
||||||
|
obj = self._compiled_obj.obj
|
||||||
|
|
||||||
|
values = []
|
||||||
|
for name in dir(obj):
|
||||||
|
try:
|
||||||
|
values.append(self[name])
|
||||||
|
except KeyError:
|
||||||
|
# The dir function can be wrong.
|
||||||
|
pass
|
||||||
|
|
||||||
|
is_instance = self._is_instance or fake.is_class_instance(obj)
|
||||||
|
# ``dir`` doesn't include the type names.
|
||||||
|
if not inspect.ismodule(obj) and obj != type and not is_instance:
|
||||||
|
values += create(self._evaluator, type).names_dict.values()
|
||||||
|
return values
|
||||||
|
|
||||||
|
|
||||||
def dotted_from_fs_path(fs_path, sys_path):
|
def dotted_from_fs_path(fs_path, sys_path):
|
||||||
"""
|
"""
|
||||||
Changes `/usr/lib/python3.4/email/utils.py` to `email.utils`. I.e.
|
Changes `/usr/lib/python3.4/email/utils.py` to `email.utils`. I.e.
|
||||||
|
|||||||
@@ -32,12 +32,12 @@ class ParserTreeFilter(AbstractFilter):
|
|||||||
def _filter(self, names, until_position):
|
def _filter(self, names, until_position):
|
||||||
names = super(ParserTreeFilter, self)._filter(names, until_position)
|
names = super(ParserTreeFilter, self)._filter(names, until_position)
|
||||||
names = [n for n in names if n.is_definition()]
|
names = [n for n in names if n.is_definition()]
|
||||||
names = [n for n in names if n.get_parent_scope() == self._parser_scope]
|
names = [n for n in names if n.parent.get_parent_scope() == self._parser_scope]
|
||||||
return names
|
return names
|
||||||
|
|
||||||
def get(self, name, until_position=None):
|
def get(self, name, until_position=None):
|
||||||
try:
|
try:
|
||||||
names = self._used_names[name]
|
names = self._used_names[str(name)]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
return []
|
return []
|
||||||
|
|
||||||
@@ -45,3 +45,14 @@ class ParserTreeFilter(AbstractFilter):
|
|||||||
|
|
||||||
def values(self, name, until_position=None):
|
def values(self, name, until_position=None):
|
||||||
return self._filter(self._used_names.values(), until_position)
|
return self._filter(self._used_names.values(), until_position)
|
||||||
|
|
||||||
|
|
||||||
|
class FunctionExecutionFilter(ParserTreeFilter):
|
||||||
|
def __init__(self, parser_scope, executed_function):
|
||||||
|
super(FunctionExecutionFilter, self).__init__(parser_scope)
|
||||||
|
self._executed_function = executed_function
|
||||||
|
|
||||||
|
def _filter(self, names, until_position):
|
||||||
|
result = super(FunctionExecutionFilter, self)._filter(names, until_position)
|
||||||
|
|
||||||
|
return [self._executed_function.name_for_position(name.start_pos) for name in result]
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ from jedi.evaluate import flow_analysis
|
|||||||
from jedi.evaluate import param
|
from jedi.evaluate import param
|
||||||
from jedi.evaluate import helpers
|
from jedi.evaluate import helpers
|
||||||
from jedi.evaluate.cache import memoize_default
|
from jedi.evaluate.cache import memoize_default
|
||||||
|
from jedi.evaluate.filters import ParserTreeFilter
|
||||||
|
|
||||||
|
|
||||||
def filter_after_position(names, position, origin=None):
|
def filter_after_position(names, position, origin=None):
|
||||||
@@ -238,6 +239,14 @@ class NameFinder(object):
|
|||||||
`names_dicts`), until a name fits.
|
`names_dicts`), until a name fits.
|
||||||
"""
|
"""
|
||||||
names = []
|
names = []
|
||||||
|
for filter in get_global_filters(self._evaluator, self.scope):
|
||||||
|
names = filter.get(self.name_str, self.position)
|
||||||
|
if names:
|
||||||
|
break
|
||||||
|
debug.dbg('finder.filter_name "%s" in (%s): %s@%s', self.name_str,
|
||||||
|
self.scope, names, self.position)
|
||||||
|
return names
|
||||||
|
|
||||||
for names_dict, position in names_dicts:
|
for names_dict, position in names_dicts:
|
||||||
names = self.names_dict_lookup(names_dict, position)
|
names = self.names_dict_lookup(names_dict, position)
|
||||||
if names:
|
if names:
|
||||||
@@ -365,6 +374,8 @@ def _name_to_types(evaluator, name, scope):
|
|||||||
types = evaluator.eval_element(typ.node_from_name(name))
|
types = evaluator.eval_element(typ.node_from_name(name))
|
||||||
elif isinstance(typ, tree.Import):
|
elif isinstance(typ, tree.Import):
|
||||||
types = imports.ImportWrapper(evaluator, name).follow()
|
types = imports.ImportWrapper(evaluator, name).follow()
|
||||||
|
elif typ.isinstance(tree.Function, tree.Class):
|
||||||
|
types = [evaluator.wrap(typ)]
|
||||||
elif typ.type == 'global_stmt':
|
elif typ.type == 'global_stmt':
|
||||||
for s in _get_global_stmt_scopes(evaluator, typ, name):
|
for s in _get_global_stmt_scopes(evaluator, typ, name):
|
||||||
finder = NameFinder(evaluator, s, str(name))
|
finder = NameFinder(evaluator, s, str(name))
|
||||||
@@ -610,6 +621,20 @@ def global_names_dict_generator(evaluator, scope, position):
|
|||||||
yield names_dict, None
|
yield names_dict, None
|
||||||
|
|
||||||
|
|
||||||
|
def get_global_filters(evaluator, context):
|
||||||
|
"""
|
||||||
|
Returns all filters in order of priority for name resolution.
|
||||||
|
"""
|
||||||
|
while context is not None:
|
||||||
|
for filter in context.get_filters(search_global=True):
|
||||||
|
yield filter
|
||||||
|
context = evaluator.wrap(context.get_parent_scope())
|
||||||
|
|
||||||
|
# Add builtins to the global scope.
|
||||||
|
for filter in evaluator.BUILTINS.get_filters(search_global=True):
|
||||||
|
yield filter
|
||||||
|
|
||||||
|
|
||||||
def check_tuple_assignments(evaluator, types, name):
|
def check_tuple_assignments(evaluator, types, name):
|
||||||
"""
|
"""
|
||||||
Checks if tuples are assigned.
|
Checks if tuples are assigned.
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ from jedi.evaluate import helpers
|
|||||||
from jedi.evaluate import param
|
from jedi.evaluate import param
|
||||||
from jedi.evaluate import flow_analysis
|
from jedi.evaluate import flow_analysis
|
||||||
from jedi.evaluate import imports
|
from jedi.evaluate import imports
|
||||||
from jedi.evaluate.filters import ParserTreeFilter
|
from jedi.evaluate.filters import ParserTreeFilter, FunctionExecutionFilter
|
||||||
|
|
||||||
|
|
||||||
class Executed(tree.Base):
|
class Executed(tree.Base):
|
||||||
@@ -665,7 +665,7 @@ class FunctionExecution(Executed):
|
|||||||
def __init__(self, evaluator, base, *args, **kwargs):
|
def __init__(self, evaluator, base, *args, **kwargs):
|
||||||
super(FunctionExecution, self).__init__(evaluator, base, *args, **kwargs)
|
super(FunctionExecution, self).__init__(evaluator, base, *args, **kwargs)
|
||||||
self._copy_dict = {}
|
self._copy_dict = {}
|
||||||
funcdef = base.base_func
|
self._original_function = funcdef = base.base_func
|
||||||
if isinstance(funcdef, mixed.MixedObject):
|
if isinstance(funcdef, mixed.MixedObject):
|
||||||
# The extra information in mixed is not needed anymore. We can just
|
# The extra information in mixed is not needed anymore. We can just
|
||||||
# unpack it and give it the tree object.
|
# unpack it and give it the tree object.
|
||||||
@@ -777,7 +777,7 @@ class FunctionExecution(Executed):
|
|||||||
del evaluator.predefined_if_name_dict_dict[for_stmt]
|
del evaluator.predefined_if_name_dict_dict[for_stmt]
|
||||||
|
|
||||||
def get_filters(self, search_global):
|
def get_filters(self, search_global):
|
||||||
yield ParserTreeFilter(self.base)
|
yield FunctionExecutionFilter(self._original_function, self.base.base_func)
|
||||||
|
|
||||||
@memoize_default(default=NO_DEFAULT)
|
@memoize_default(default=NO_DEFAULT)
|
||||||
def _get_params(self):
|
def _get_params(self):
|
||||||
|
|||||||
Reference in New Issue
Block a user