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.parser.tree import Param, Base, Operator
|
||||
from jedi.evaluate.helpers import FakeName
|
||||
from jedi.evaluate.filters import AbstractFilter
|
||||
from . import fake
|
||||
|
||||
|
||||
@@ -156,6 +157,9 @@ class CompiledObject(Base):
|
||||
def names_dicts(self, search_global, is_instance=False):
|
||||
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
|
||||
def _names_dict_ensure_one_dict(self, is_instance):
|
||||
"""
|
||||
@@ -164,6 +168,14 @@ class CompiledObject(Base):
|
||||
"""
|
||||
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):
|
||||
if name in dir(self.obj):
|
||||
return CompiledName(self._evaluator, self, name).parent
|
||||
@@ -314,6 +326,50 @@ class LazyNamesDict(object):
|
||||
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):
|
||||
"""
|
||||
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):
|
||||
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.get_parent_scope() == self._parser_scope]
|
||||
names = [n for n in names if n.parent.get_parent_scope() == self._parser_scope]
|
||||
return names
|
||||
|
||||
def get(self, name, until_position=None):
|
||||
try:
|
||||
names = self._used_names[name]
|
||||
names = self._used_names[str(name)]
|
||||
except KeyError:
|
||||
return []
|
||||
|
||||
@@ -45,3 +45,14 @@ class ParserTreeFilter(AbstractFilter):
|
||||
|
||||
def values(self, name, until_position=None):
|
||||
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 helpers
|
||||
from jedi.evaluate.cache import memoize_default
|
||||
from jedi.evaluate.filters import ParserTreeFilter
|
||||
|
||||
|
||||
def filter_after_position(names, position, origin=None):
|
||||
@@ -238,6 +239,14 @@ class NameFinder(object):
|
||||
`names_dicts`), until a name fits.
|
||||
"""
|
||||
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:
|
||||
names = self.names_dict_lookup(names_dict, position)
|
||||
if names:
|
||||
@@ -365,6 +374,8 @@ def _name_to_types(evaluator, name, scope):
|
||||
types = evaluator.eval_element(typ.node_from_name(name))
|
||||
elif isinstance(typ, tree.Import):
|
||||
types = imports.ImportWrapper(evaluator, name).follow()
|
||||
elif typ.isinstance(tree.Function, tree.Class):
|
||||
types = [evaluator.wrap(typ)]
|
||||
elif typ.type == 'global_stmt':
|
||||
for s in _get_global_stmt_scopes(evaluator, typ, name):
|
||||
finder = NameFinder(evaluator, s, str(name))
|
||||
@@ -610,6 +621,20 @@ def global_names_dict_generator(evaluator, scope, position):
|
||||
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):
|
||||
"""
|
||||
Checks if tuples are assigned.
|
||||
|
||||
@@ -55,7 +55,7 @@ from jedi.evaluate import helpers
|
||||
from jedi.evaluate import param
|
||||
from jedi.evaluate import flow_analysis
|
||||
from jedi.evaluate import imports
|
||||
from jedi.evaluate.filters import ParserTreeFilter
|
||||
from jedi.evaluate.filters import ParserTreeFilter, FunctionExecutionFilter
|
||||
|
||||
|
||||
class Executed(tree.Base):
|
||||
@@ -665,7 +665,7 @@ class FunctionExecution(Executed):
|
||||
def __init__(self, evaluator, base, *args, **kwargs):
|
||||
super(FunctionExecution, self).__init__(evaluator, base, *args, **kwargs)
|
||||
self._copy_dict = {}
|
||||
funcdef = base.base_func
|
||||
self._original_function = funcdef = base.base_func
|
||||
if isinstance(funcdef, mixed.MixedObject):
|
||||
# The extra information in mixed is not needed anymore. We can just
|
||||
# unpack it and give it the tree object.
|
||||
@@ -777,7 +777,7 @@ class FunctionExecution(Executed):
|
||||
del evaluator.predefined_if_name_dict_dict[for_stmt]
|
||||
|
||||
def get_filters(self, search_global):
|
||||
yield ParserTreeFilter(self.base)
|
||||
yield FunctionExecutionFilter(self._original_function, self.base.base_func)
|
||||
|
||||
@memoize_default(default=NO_DEFAULT)
|
||||
def _get_params(self):
|
||||
|
||||
Reference in New Issue
Block a user