1
0
forked from VimPlug/jedi

Start implemeting contexts with specialized TreeNameDefinitions to avoid gambling with the parser.

This commit is contained in:
Dave Halter
2016-10-20 19:36:44 +02:00
parent 3654de97b0
commit cad9ae8ab1
9 changed files with 178 additions and 111 deletions

View File

@@ -29,6 +29,7 @@ def get_call_signature_param_names(call_signatures):
def filter_names(evaluator, completion_names, stack, like_name):
comp_dct = {}
for name in set(completion_names):
print(name)
if settings.case_insensitive_completion \
and str(name).lower().startswith(like_name.lower()) \
or str(name).startswith(like_name):
@@ -193,11 +194,11 @@ class Completion:
def _trailer_completions(self, atom_expr):
user_scope = get_user_scope(self._module, self._position)
scopes = self._evaluator.eval_element(atom_expr)
contexts = self._evaluator.eval_element(self._evaluator.create_context(atom_expr), atom_expr)
completion_names = []
debug.dbg('trailer completion scopes: %s', scopes)
for s in scopes:
for filter in s.get_filters(search_global=False, origin_scope=user_scope):
debug.dbg('trailer completion contexts: %s', contexts)
for context in contexts:
for filter in context.get_filters(search_global=False, origin_scope=user_scope):
completion_names += filter.values()
return completion_names

View File

@@ -5,7 +5,7 @@ import copy
from jedi.cache import underscore_memoization
from jedi.evaluate import helpers
from jedi.evaluate.representation import ModuleWrapper
from jedi.evaluate.representation import ModuleContext
from jedi.evaluate.compiled import mixed
@@ -18,7 +18,7 @@ class MixedModule(object):
self._namespaces = namespaces
self._namespace_objects = [type('jedi_namespace', (), n) for n in namespaces]
self._wrapped_module = ModuleWrapper(evaluator, parser_module)
self._wrapped_module = ModuleContext(evaluator, parser_module)
# Usually we are dealing with very small code sizes when it comes to
# interpreter modules. In this case we just copy the whole syntax tree
# to be able to modify it.

View File

@@ -109,20 +109,20 @@ class Evaluator(object):
self.recursion_detector = recursion.RecursionDetector(self)
self.execution_recursion_detector = recursion.ExecutionRecursionDetector(self)
def wrap(self, element):
def wrap(self, element, parent_context=None):
if isinstance(element, (er.Wrapper, er.InstanceElement,
er.ModuleWrapper, er.FunctionExecution, er.Instance, compiled.CompiledObject)) or element is None:
er.ModuleContext, er.FunctionExecution, er.Instance, compiled.CompiledObject)) or element is None:
# TODO this is so ugly, please refactor.
return element
if element.type == 'classdef':
return er.Class(self, element)
return er.ClassContext(self, element, parent_context)
elif element.type == 'funcdef':
return er.Function(self, element)
elif element.type == 'lambda':
return er.LambdaWrapper(self, element)
elif element.type == 'file_input':
return er.ModuleWrapper(self, element)
return er.ModuleContext(self, element)
else:
return element
@@ -145,7 +145,7 @@ class Evaluator(object):
#@memoize_default(default=[], evaluator_is_first_arg=True)
#@recursion.recursion_decorator
@debug.increase_indent
def eval_statement(self, stmt, seek_name=None):
def eval_statement(self, context, stmt, seek_name=None):
"""
The starting point of the completion. A statement always owns a call
list, which are the calls, that a statement does. In case multiple
@@ -156,7 +156,7 @@ class Evaluator(object):
"""
debug.dbg('eval_statement %s (%s)', stmt, seek_name)
rhs = stmt.get_rhs()
types = self.eval_element(rhs)
types = self.eval_element(context, rhs)
if seek_name:
types = finder.check_tuple_assignments(self, types, seek_name)
@@ -177,13 +177,13 @@ class Evaluator(object):
# only in for loops without clutter, because they are
# predictable. Also only do it, if the variable is not a tuple.
node = for_stmt.get_input_node()
for_iterables = self.eval_element(node)
for_iterables = self.eval_element(context, node)
ordered = list(iterable.py__iter__(self, for_iterables, node))
for index_types in ordered:
dct = {str(for_stmt.children[1]): index_types}
self.predefined_if_name_dict_dict[for_stmt] = dct
t = self.eval_element(rhs)
t = self.eval_element(context, rhs)
left = precedence.calculate(self, left, operator, t)
types = left
if ordered:
@@ -196,11 +196,11 @@ class Evaluator(object):
debug.dbg('eval_statement result %s', types)
return types
def eval_element(self, element):
def eval_element(self, context, element):
if isinstance(element, iterable.AlreadyEvaluated):
return set(element)
elif isinstance(element, iterable.MergedNodes):
return iterable.unite(self.eval_element(e) for e in element)
return iterable.unite(self.eval_element(context, e) for e in element)
if_stmt = element.get_parent_until((tree.IfStmt, tree.ForStmt, tree.IsScope))
predefined_if_name_dict = self.predefined_if_name_dict_dict.get(if_stmt)
@@ -249,21 +249,21 @@ class Evaluator(object):
for name_dict in name_dicts:
self.predefined_if_name_dict_dict[if_stmt] = name_dict
try:
result |= self._eval_element_not_cached(element)
result |= self._eval_element_not_cached(context, element)
finally:
del self.predefined_if_name_dict_dict[if_stmt]
return result
else:
return self._eval_element_if_evaluated(element)
return self._eval_element_cached(element)
return self._eval_element_if_evaluated(context, element)
return self._eval_element_cached(context, element)
else:
if predefined_if_name_dict:
return self._eval_element_not_cached(element)
return self._eval_element_not_cached(context, element)
else:
return self._eval_element_if_evaluated(element)
return self._eval_element_cached(element)
return self._eval_element_if_evaluated(context, element)
return self._eval_element_cached(context, element)
def _eval_element_if_evaluated(self, element):
def _eval_element_if_evaluated(self, context, element):
"""
TODO This function is temporary: Merge with eval_element.
"""
@@ -272,19 +272,19 @@ class Evaluator(object):
parent = parent.parent
predefined_if_name_dict = self.predefined_if_name_dict_dict.get(parent)
if predefined_if_name_dict is not None:
return self._eval_element_not_cached(element)
return self._eval_element_cached(element)
return self._eval_element_not_cached(context, element)
return self._eval_element_cached(context, element)
@memoize_default(default=set(), evaluator_is_first_arg=True)
def _eval_element_cached(self, element):
return self._eval_element_not_cached(element)
def _eval_element_cached(self, context, element):
return self._eval_element_not_cached(context, element)
@debug.increase_indent
def _eval_element_not_cached(self, element):
def _eval_element_not_cached(self, context, element):
debug.dbg('eval_element %s@%s', element, element.start_pos)
types = set()
if isinstance(element, (tree.Name, tree.Literal)) or tree.is_node(element, 'atom'):
types = self._eval_atom(element)
types = self._eval_atom(context, element)
elif isinstance(element, tree.Keyword):
# For False/True/None
if element.value in ('False', 'True', 'None'):
@@ -295,12 +295,12 @@ class Evaluator(object):
elif element.isinstance(er.LambdaWrapper):
types = set([element]) # TODO this is no real evaluation.
elif element.type == 'expr_stmt':
types = self.eval_statement(element)
types = self.eval_statement(context, element)
elif element.type in ('power', 'atom_expr'):
types = self._eval_atom(element.children[0])
types = self._eval_atom(context, element.children[0])
for trailer in element.children[1:]:
if trailer == '**': # has a power operation.
right = self.eval_element(element.children[2])
right = self.eval_element(context, element.children[2])
types = set(precedence.calculate(self, types, trailer, right))
break
types = self.eval_trailer(types, trailer)
@@ -308,31 +308,31 @@ class Evaluator(object):
# The implicit tuple in statements.
types = set([iterable.ImplicitTuple(self, element)])
elif element.type in ('not_test', 'factor'):
types = self.eval_element(element.children[-1])
types = self.eval_element(context, element.children[-1])
for operator in element.children[:-1]:
types = set(precedence.factor_calculate(self, types, operator))
elif element.type == 'test':
# `x if foo else y` case.
types = (self.eval_element(element.children[0]) |
self.eval_element(element.children[-1]))
types = (self.eval_element(context, element.children[0]) |
self.eval_element(context, element.children[-1]))
elif element.type == 'operator':
# Must be an ellipsis, other operators are not evaluated.
assert element.value == '...'
types = set([compiled.create(self, Ellipsis)])
elif element.type == 'dotted_name':
types = self._eval_atom(element.children[0])
types = self._eval_atom(context, element.children[0])
for next_name in element.children[2::2]:
types = set(chain.from_iterable(self.find_types(typ, next_name)
for typ in types))
types = types
elif element.type == 'eval_input':
types = self._eval_element_not_cached(element.children[0])
types = self._eval_element_not_cached(context, element.children[0])
else:
types = precedence.calculate_children(self, element.children)
debug.dbg('eval_element result %s', types)
return types
def _eval_atom(self, atom):
def _eval_atom(self, context, atom):
"""
Basically to process ``atom`` nodes. The parser sometimes doesn't
generate the node (because it has just one child). In that case an atom
@@ -442,25 +442,25 @@ class Evaluator(object):
debug.dbg('execute result: %s in %s', types, obj)
return types
def goto_definitions(self, name):
def goto_definitions(self, context, name):
def_ = name.get_definition()
is_simple_name = name.parent.type not in ('power', 'trailer')
if is_simple_name:
if name.parent.type in ('file_input', 'classdef', 'funcdef'):
return [self.wrap(name.parent)]
if def_.type == 'expr_stmt' and name in def_.get_defined_names():
return self.eval_statement(def_, name)
return self.eval_statement(context, def_, name)
elif def_.type == 'for_stmt':
container_types = self.eval_element(def_.children[3])
container_types = self.eval_element(context, def_.children[3])
for_types = iterable.py__iter__types(self, container_types, def_.children[3])
return finder.check_tuple_assignments(self, for_types, name)
elif def_.type in ('import_from', 'import_name'):
return imports.ImportWrapper(self, name).follow()
call = helpers.call_of_leaf(name)
return self.eval_element(call)
return self.eval_element(context, call)
def goto(self, name):
def goto(self, context, name):
def resolve_implicit_imports(names):
for name in names:
if isinstance(name.parent, helpers.FakeImport):
@@ -480,13 +480,13 @@ class Evaluator(object):
trailer = trailer.parent
if trailer.type != 'classdef':
if trailer.type == 'decorator':
types = self.eval_element(trailer.children[1])
types = self.eval_element(context, trailer.children[1])
else:
i = trailer.parent.children.index(trailer)
to_evaluate = trailer.parent.children[:i]
types = self.eval_element(to_evaluate[0])
types = self.eval_element(context, to_evaluate[0])
for trailer in to_evaluate[1:]:
types = self.eval_trailer(types, trailer)
types = self.eval_trailer(context, types, trailer)
param_names = []
for typ in types:
try:
@@ -511,7 +511,7 @@ class Evaluator(object):
if index > 0:
new_dotted = helpers.deep_ast_copy(par)
new_dotted.children[index - 1:] = []
types = self.eval_element(new_dotted)
types = self.eval_element(context, new_dotted)
return resolve_implicit_imports(iterable.unite(
self.find_types(typ, name, is_goto=True) for typ in types
))
@@ -519,7 +519,7 @@ class Evaluator(object):
scope = name.get_parent_scope()
if tree.is_node(par, 'trailer') and par.children[0] == '.':
call = helpers.call_of_leaf(name, cut_own_trailer=True)
types = self.eval_element(call)
types = self.eval_element(context, call)
return resolve_implicit_imports(iterable.unite(
self.find_types(typ, name, is_goto=True) for typ in types
))
@@ -530,3 +530,9 @@ class Evaluator(object):
stmt = name
return self.find_types(scope, name, stmt.start_pos,
search_global=True, is_goto=True)
def create_context(self, node):
scope = node.get_parent_scope()
if scope.get_parent_scope() is not None:
raise NotImplementedError
return self.wrap(scope)

View File

@@ -271,15 +271,10 @@ class CompiledName(FakeName):
def is_definition(self):
return True
@property
@underscore_memoization
def parent(self):
def infer(self):
module = self._compiled_obj.get_parent_until()
return _create_from_name(self._evaluator, module, self._compiled_obj, self.name)
@parent.setter
def parent(self, value):
pass # Just ignore this, FakeName tries to overwrite the parent attribute.
return [_create_from_name(self._evaluator, module, self._compiled_obj, self.name)]
class LazyNamesDict(object):

View File

@@ -9,6 +9,44 @@ from jedi.evaluate import flow_analysis
from jedi.common import to_list
class AbstractNameDefinition(object):
start_pos = None
@property
@abstractmethod
def string_name(self):
raise NotImplementedError
@abstractmethod
def infer(self):
raise NotImplementedError
class TreeNameDefinition(AbstractNameDefinition):
def __init__(self, parent_context, name):
self.parent_context = parent_context
self._name = name
def get_parent_flow_context(self):
return self.parent_context
@property
def string_name(self):
return self._name.value
@property
def start_pos(self):
return self._name.start_pos
def infer(self):
# Refactor this, should probably be here.
from jedi.evaluate.finder import _name_to_types
return _name_to_types(self.parent_context._evaluator, self.parent_context, self._name, None)
def __repr__(self):
return '%s: %s@%s' % (type(self).__name__, self.string_name, self.start_pos)
class AbstractFilter(object):
_until_position = None
@@ -30,10 +68,11 @@ class AbstractFilter(object):
class AbstractUsedNamesFilter(AbstractFilter):
def __init__(self, parser_scope, origin_scope=None):
def __init__(self, context, parser_scope, origin_scope=None):
super(AbstractUsedNamesFilter, self).__init__(origin_scope)
self._parser_scope = parser_scope
self._used_names = self._parser_scope.get_root_node().used_names
self._context = context
def get(self, name):
try:
@@ -41,16 +80,19 @@ class AbstractUsedNamesFilter(AbstractFilter):
except KeyError:
return []
return list(self._filter(names))
return self._convert_to_names(self._filter(names))
def _convert_to_names(self, names):
return [TreeNameDefinition(self._context, name) for name in names]
def values(self):
return [name for name_list in self._used_names.values()
for name in self._filter(name_list)]
return self._convert_to_names(name for name_list in self._used_names.values()
for name in self._filter(name_list))
class ParserTreeFilter(AbstractUsedNamesFilter):
def __init__(self, evaluator, parser_scope, until_position=None, origin_scope=None):
super(ParserTreeFilter, self).__init__(parser_scope, origin_scope)
def __init__(self, evaluator, context, parser_scope, until_position=None, origin_scope=None):
super(ParserTreeFilter, self).__init__(context, parser_scope, origin_scope)
self._until_position = until_position
self._evaluator = evaluator
@@ -65,8 +107,9 @@ class ParserTreeFilter(AbstractUsedNamesFilter):
for name in sorted(names, key=lambda name: name.start_pos, reverse=True):
stmt = name.get_definition()
name_scope = self._evaluator.wrap(stmt.get_parent_scope())
check = flow_analysis.break_check(self._evaluator, name_scope,
stmt, self._origin_scope)
check = flow_analysis.UNSURE
#check = flow_analysis.break_check(self._evaluator, name_scope,
# stmt, self._origin_scope)
if check is not flow_analysis.UNREACHABLE:
yield name
@@ -75,7 +118,7 @@ class ParserTreeFilter(AbstractUsedNamesFilter):
class FunctionExecutionFilter(ParserTreeFilter):
def __init__(self, evaluator, parser_scope, executed_function, param_by_name,
def __init__(self, evaluator, context, parser_scope, executed_function, param_by_name,
until_position=None, origin_scope=None):
super(FunctionExecutionFilter, self).__init__(
evaluator,
@@ -96,8 +139,8 @@ class FunctionExecutionFilter(ParserTreeFilter):
class GlobalNameFilter(AbstractUsedNamesFilter):
def __init__(self, parser_scope, origin_scope=None):
super(GlobalNameFilter, self).__init__(parser_scope)
def __init__(self, context, parser_scope, origin_scope=None):
super(GlobalNameFilter, self).__init__(context, parser_scope)
@to_list
def _filter(self, names):
@@ -141,7 +184,7 @@ def get_global_filters(evaluator, context, until_position, origin_scope):
until_position = None
in_func = True
node = context.get_parent_scope()
node = context.parent_context
context = evaluator.wrap(node)
# Add builtins to the global scope.

View File

@@ -179,7 +179,7 @@ class NameFinder(object):
last_names.append(name)
continue
if isinstance(stmt, er.ModuleWrapper):
if isinstance(stmt, er.ModuleContext):
# In case of REPL completion, we can infer modules names that
# don't really have a definition (because they are really just
# namespaces). In this case we can just add it.
@@ -258,17 +258,19 @@ class NameFinder(object):
wrapper parents. We don't want to see AST classes out in the
evaluation, so remove them already here!
"""
for n in names:
definition = n.parent
if isinstance(definition, (compiled.CompiledObject,
iterable.BuiltinMethod)):
# TODO this if should really be removed by changing the type of
# those classes.
yield n
elif definition.type in ('funcdef', 'classdef', 'file_input'):
yield self._evaluator.wrap(definition).name
else:
yield n
return names
#for n in names:
# definition = n.parent
# if isinstance(definition, (compiled.CompiledObject,
# iterable.BuiltinMethod)):
# # TODO this if should really be removed by changing the type of
# # those classes.
# yield n
# elif definition.type in ('funcdef', 'classdef', 'file_input'):
# yield self._evaluator.wrap(definition).name
# else:
# yield n
def _check_getattr(self, inst):
"""Checks for both __getattr__ and __getattribute__ methods"""
@@ -308,8 +310,8 @@ class NameFinder(object):
return n
for name in names:
new_types = _name_to_types(self._evaluator, name, self.scope)
if isinstance(self.scope, (er.Class, er.Instance)) and attribute_lookup:
new_types = name.infer()
if isinstance(self.scope, (er.ClassContext, er.Instance)) and attribute_lookup:
types |= set(self._resolve_descriptors(name, new_types))
else:
types |= set(new_types)
@@ -347,7 +349,7 @@ def _get_global_stmt_scopes(evaluator, global_stmt, name):
@memoize_default(set(), evaluator_is_first_arg=True)
def _name_to_types(evaluator, name, scope):
def _name_to_types(evaluator, context, name, scope):
types = []
typ = name.get_definition()
if typ.isinstance(tree.ForStmt):
@@ -365,7 +367,7 @@ def _name_to_types(evaluator, name, scope):
elif isinstance(typ, tree.Param):
types = _eval_param(evaluator, typ, scope)
elif typ.isinstance(tree.ExprStmt):
types = _remove_statements(evaluator, typ, name)
types = _remove_statements(evaluator, context, typ, name)
elif typ.isinstance(tree.WithStmt):
types = evaluator.eval_element(typ.node_from_name(name))
elif isinstance(typ, tree.Import):
@@ -393,7 +395,7 @@ def _name_to_types(evaluator, name, scope):
return types
def _remove_statements(evaluator, stmt, name):
def _remove_statements(evaluator, context, stmt, name):
"""
This is the part where statements are being stripped.
@@ -415,7 +417,7 @@ def _remove_statements(evaluator, stmt, name):
pep0484.find_type_from_comment_hint_assign(evaluator, stmt, name)
if pep0484types:
return pep0484types
types |= evaluator.eval_statement(stmt, seek_name=name)
types |= evaluator.eval_statement(context, stmt, seek_name=name)
if check_instance is not None:
# class renames

View File

@@ -33,6 +33,7 @@ UNSURE = Status(None, 'unsure')
def break_check(evaluator, base_scope, stmt, origin_scope=None):
raise NotImplementedError
element_scope = evaluator.wrap(stmt.get_parent_scope(include_flows=True))
# Direct parents get resolved, we filter scopes that are separate branches.
# This makes sense for autocompletion and static analysis. For actual

View File

@@ -30,7 +30,7 @@ def try_iter_content(types, depth=0):
class Arguments(tree.Base):
def __init__(self, evaluator, argument_node, trailer=None):
def __init__(self, evaluator, context, argument_node, trailer=None):
"""
The argument_node is either a parser node or a list of evaluated
objects. Those evaluated objects may be lists of evaluated objects
@@ -39,6 +39,7 @@ class Arguments(tree.Base):
:param argument_node: May be an argument_node or a list of nodes.
"""
self.argument_node = argument_node
self._context = context
self._evaluator = evaluator
self.trailer = trailer # Can be None, e.g. in a class definition.
@@ -73,7 +74,7 @@ class Arguments(tree.Base):
element = self.argument_node[0]
from jedi.evaluate.iterable import AlreadyEvaluated
if isinstance(element, AlreadyEvaluated):
element = list(self._evaluator.eval_element(element))[0]
element = list(self._evaluator.eval_element(self._context, element))[0]
except IndexError:
return None
else:
@@ -93,14 +94,14 @@ class Arguments(tree.Base):
named_args = []
for stars, el in self._split():
if stars == 1:
arrays = self._evaluator.eval_element(el)
arrays = self._evaluator.eval_element(self._context, el)
iterators = [_iterate_star_args(self._evaluator, a, el, func)
for a in arrays]
iterators = list(iterators)
for values in list(zip_longest(*iterators)):
yield None, [v for v in values if v is not None]
elif stars == 2:
arrays = self._evaluator.eval_element(el)
arrays = self._evaluator.eval_element(self._context, el)
dicts = [_star_star_dict(self._evaluator, a, el, func)
for a in arrays]
for dct in dicts:
@@ -155,7 +156,7 @@ class Arguments(tree.Base):
debug.warning('TypeError: %s expected at least %s arguments, got %s',
name, len(arguments), i)
raise ValueError
values = set(chain.from_iterable(self._evaluator.eval_element(el)
values = set(chain.from_iterable(self._evaluator.eval_element(self._context, el)
for el in va_values))
if not values and not optional:
# For the stdlib we always want values. If we don't get them,
@@ -172,7 +173,7 @@ class Arguments(tree.Base):
def eval_args(self):
# TODO this method doesn't work with named args and a lot of other
# things. Use unpack.
return [self._evaluator.eval_element(el) for stars, el in self._split()]
return [self._evaluator.eval_element(self._context, el) for stars, el in self._split()]
def __repr__(self):
return '<%s: %s>' % (type(self).__name__, self.argument_node)
@@ -191,7 +192,7 @@ class Arguments(tree.Base):
"""
for key, element_values in self.unpack():
for element in element_values:
types = self._evaluator.eval_element(element)
types = self._evaluator.eval_element(self._context, element)
try_iter_content(types)

View File

@@ -59,6 +59,21 @@ from jedi.evaluate.filters import ParserTreeFilter, FunctionExecutionFilter, \
GlobalNameFilter, DictFilter
class Context(object):
def __init__(self, evaluator, parent_context=None):
self._evaluator = evaluator
self.parent_context = parent_context
def get_parent_flow_context(self):
return self.parent_context
class FlowContext(Context):
def get_parent_flow_context(self):
if 1:
return self.parent_context
class Executed(tree.Base):
"""
An instance is also an executable - because __init__ is called
@@ -152,7 +167,7 @@ class Instance(use_metaclass(CachedMetaClass, Executed)):
# This loop adds the names of the self object, copies them and removes
# the self.
for sub in self.base.subscopes:
if isinstance(sub, tree.Class):
if isinstance(sub, tree.ClassContext):
continue
# Get the self name, if there's one.
self_name = self._get_func_self_name(sub)
@@ -292,18 +307,18 @@ class CompiledInstanceClassFilter(compiled.CompiledObjectFilter):
class InstanceClassFilter(ParserTreeFilter):
def __init__(self, evaluator, instance, parser_scope, origin_scope):
def __init__(self, evaluator, context, parser_scope, origin_scope):
super(InstanceClassFilter, self).__init__(
evaluator=evaluator,
context=context,
parser_scope=parser_scope,
origin_scope=origin_scope
)
self._instance = instance
def _equals_origin_scope(self):
node = self._origin_scope
while node is not None:
if node == self._parser_scope or node == self._instance:
if node == self._parser_scope or node == self._context:
return True
node = node.get_parent_scope()
return False
@@ -314,7 +329,7 @@ class InstanceClassFilter(ParserTreeFilter):
def _filter(self, names):
names = super(InstanceClassFilter, self)._filter(names)
return [get_instance_el(self._evaluator, self._instance, name, True)
return [get_instance_el(self._evaluator, self._context, name, True)
for name in names if self._access_possible(name)]
def _check_flows(self, names):
@@ -337,12 +352,12 @@ class SelfNameFilter(InstanceClassFilter):
and len(trailer.children) == 2 \
and trailer.children[0] == '.':
if name.is_definition() and self._access_possible(name):
init_execution = self._instance._get_init_execution()
init_execution = self._context._get_init_execution()
# Hopefully we can somehow change this.
if init_execution is not None and \
init_execution.start_pos < name.start_pos < init_execution.end_pos:
name = init_execution.name_for_position(name.start_pos)
yield get_instance_el(self._evaluator, self._instance, name)
yield get_instance_el(self._evaluator, self._context, name)
class LazyInstanceDict(object):
@@ -406,8 +421,8 @@ class InstanceElement(use_metaclass(CachedMetaClass, tree.Base)):
@memoize_default()
def parent(self):
par = self.var.parent
if isinstance(par, Class) and par == self.instance.base \
or not isinstance(self.instance.base, (tree.Class, Class)) \
if isinstance(par, ClassContext) and par == self.instance.base \
or not isinstance(self.instance.base, (tree.Class, ClassContext)) \
or isinstance(par, tree.Class) \
and par == self.instance.base.base:
par = self.instance
@@ -501,13 +516,13 @@ class Wrapper(tree.Base):
return helpers.FakeName(unicode(name), self, name.start_pos)
class Class(use_metaclass(CachedMetaClass, Wrapper)):
class ClassContext(use_metaclass(CachedMetaClass, Context, Wrapper)):
"""
This class is not only important to extend `tree.Class`, it is also a
important for descriptors (if the descriptor methods are evaluated or not).
"""
def __init__(self, evaluator, base):
self._evaluator = evaluator
def __init__(self, evaluator, base, parent_context):
super(ClassContext, self).__init__(evaluator, parent_context=parent_context)
self.base = base
@memoize_default(default=())
@@ -547,7 +562,7 @@ class Class(use_metaclass(CachedMetaClass, Wrapper)):
def py__bases__(self):
arglist = self.base.get_super_arglist()
if arglist:
args = param.Arguments(self._evaluator, arglist)
args = param.Arguments(self._evaluator, self, arglist)
return list(chain.from_iterable(args.eval_args()))
else:
return [compiled.create(self._evaluator, object)]
@@ -577,14 +592,14 @@ class Class(use_metaclass(CachedMetaClass, Wrapper)):
def get_filters(self, search_global, until_position=None, origin_scope=None, is_instance=False):
if search_global:
yield ParserTreeFilter(self._evaluator, self.base, until_position, origin_scope=origin_scope)
yield ParserTreeFilter(self._evaluator, self, self.base, until_position, origin_scope=origin_scope)
else:
for scope in self.py__mro__():
if isinstance(scope, compiled.CompiledObject):
for filter in scope.get_filters(is_instance=is_instance):
yield filter
else:
yield ParserTreeFilter(self._evaluator, scope.base, origin_scope=origin_scope)
yield ParserTreeFilter(self._evaluator, self, scope.base, origin_scope=origin_scope)
def is_class(self):
return True
@@ -684,7 +699,7 @@ class Function(use_metaclass(CachedMetaClass, Wrapper)):
def get_filters(self, search_global, until_position=None, origin_scope=None):
if search_global:
yield ParserTreeFilter(self._evaluator, self.base, until_position, origin_scope=origin_scope)
yield ParserTreeFilter(self._evaluator, self, self.base, until_position, origin_scope=origin_scope)
else:
scope = self.py__class__()
for filter in scope.get_filters(search_global=False, origin_scope=origin_scope):
@@ -862,7 +877,7 @@ class FunctionExecution(Executed):
del evaluator.predefined_if_name_dict_dict[for_stmt]
def get_filters(self, search_global, until_position=None, origin_scope=None):
yield FunctionExecutionFilter(self._evaluator, self._original_function,
yield FunctionExecutionFilter(self._evaluator, self, self._original_function,
self._copied_funcdef,
self.param_by_name,
until_position,
@@ -923,7 +938,9 @@ class GlobalName(helpers.FakeName):
name.start_pos, is_definition=True)
class ModuleWrapper(use_metaclass(CachedMetaClass, tree.Module, Wrapper)):
class ModuleContext(use_metaclass(CachedMetaClass, tree.Module, Wrapper)):
parent_context = None
def __init__(self, evaluator, module, parent_module=None):
self._evaluator = evaluator
self.base = self._module = module
@@ -942,11 +959,12 @@ class ModuleWrapper(use_metaclass(CachedMetaClass, tree.Module, Wrapper)):
def get_filters(self, search_global, until_position=None, origin_scope=None):
yield ParserTreeFilter(
self._evaluator,
self,
self._module,
until_position,
origin_scope=origin_scope
)
yield GlobalNameFilter(self._module)
yield GlobalNameFilter(self, self._module)
yield DictFilter(self._sub_modules_dict())
yield DictFilter(self._module_attributes_dict())
# TODO