From ba03f1dcb915af3cc400f530bcca4aa47eac9c28 Mon Sep 17 00:00:00 2001 From: Dave Halter Date: Wed, 16 Nov 2016 21:16:12 +0100 Subject: [PATCH] Fix properties. --- jedi/evaluate/compiled/__init__.py | 5 +- jedi/evaluate/filters.py | 2 +- jedi/evaluate/finder.py | 21 ++++--- jedi/evaluate/instance.py | 88 +++++++++++++++++++++--------- 4 files changed, 80 insertions(+), 36 deletions(-) diff --git a/jedi/evaluate/compiled/__init__.py b/jedi/evaluate/compiled/__init__.py index 9320c4e1..8ccd20dd 100644 --- a/jedi/evaluate/compiled/__init__.py +++ b/jedi/evaluate/compiled/__init__.py @@ -364,7 +364,7 @@ class CompiledObjectFilter(AbstractFilter): # 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)] + return [self._create(name)] def values(self): obj = self._compiled_obj.obj @@ -380,6 +380,9 @@ class CompiledObjectFilter(AbstractFilter): names += filter.values() return names + def _create(self, name): + return self.name_class(self._evaluator, self._compiled_obj, name) + def dotted_from_fs_path(fs_path, sys_path): """ diff --git a/jedi/evaluate/filters.py b/jedi/evaluate/filters.py index 49fec3cd..c326589c 100644 --- a/jedi/evaluate/filters.py +++ b/jedi/evaluate/filters.py @@ -59,7 +59,7 @@ class TreeNameDefinition(ContextName): 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.tree_name, None) + return _name_to_types(self.parent_context.evaluator, self.parent_context, self.tree_name) class ParamName(ContextName): diff --git a/jedi/evaluate/finder.py b/jedi/evaluate/finder.py index 372eae9e..25721f3e 100644 --- a/jedi/evaluate/finder.py +++ b/jedi/evaluate/finder.py @@ -22,6 +22,7 @@ from jedi import debug from jedi.common import unite from jedi import settings from jedi.evaluate import representation as er +from jedi.evaluate.instance import AbstractInstanceContext from jedi.evaluate import dynamic from jedi.evaluate import compiled from jedi.evaluate import docstrings @@ -32,9 +33,8 @@ from jedi.evaluate import analysis from jedi.evaluate import flow_analysis from jedi.evaluate import param from jedi.evaluate import helpers -from jedi.evaluate.instance import AbstractInstanceContext from jedi.evaluate.cache import memoize_default -from jedi.evaluate.filters import get_global_filters +from jedi.evaluate.filters import get_global_filters, ContextName def filter_after_position(names, position, origin=None): @@ -321,7 +321,8 @@ class NameFinder(object): for name in names: new_types = name.infer() - if isinstance(self.context, (er.ClassContext, er.Instance)) and attribute_lookup: + if isinstance(self.context, (er.ClassContext, AbstractInstanceContext)) \ + and attribute_lookup: types |= set(self._resolve_descriptors(name, new_types)) else: types |= set(new_types) @@ -334,6 +335,10 @@ class NameFinder(object): return types def _resolve_descriptors(self, name, types): + if not isinstance(name, ContextName): + # Compiled names and other stuff should just be ignored when it + # comes to descriptors. + return types # The name must not be in the dictionary, but part of the class # definition. __get__ is only called if the descriptor is defined in # the class dictionary. @@ -353,7 +358,7 @@ class NameFinder(object): @memoize_default(set(), evaluator_is_first_arg=True) -def _name_to_types(evaluator, context, name, scope): +def _name_to_types(evaluator, context, name): types = [] node = name.get_definition() if node.isinstance(tree.ForStmt): @@ -370,7 +375,7 @@ def _name_to_types(evaluator, context, name, scope): types = check_tuple_assignments(evaluator, for_types, name) elif isinstance(node, tree.Param): return set() # TODO remove - types = _eval_param(evaluator, context, node, scope) + types = _eval_param(evaluator, context, node) elif node.isinstance(tree.ExprStmt): types = _remove_statements(evaluator, context, node, name) elif node.isinstance(tree.WithStmt): @@ -423,10 +428,10 @@ def _apply_decorators(evaluator, context, node): for dec in reversed(node.get_decorators()): debug.dbg('decorator: %s %s', dec, values) dec_values = context.eval_node(dec.children[1]) - trailer = dec.children[2:-1] - if trailer: + trailer_nodes = dec.children[2:-1] + if trailer_nodes: # Create a trailer and evaluate it. - trailer = tree.Node('trailer', trailer) + trailer = tree.Node('trailer', trailer_nodes) trailer.parent = dec dec_values = evaluator.eval_trailer(context, dec_values, trailer) diff --git a/jedi/evaluate/instance.py b/jedi/evaluate/instance.py index 3305faed..b5b89829 100644 --- a/jedi/evaluate/instance.py +++ b/jedi/evaluate/instance.py @@ -142,24 +142,10 @@ class AbstractInstanceContext(Context): def name(self): pass - def __repr__(self): - return "<%s of %s(%s)>" % (self.__class__.__name__, self.class_context, - self.var_args) - - -class CompiledInstance(AbstractInstanceContext): - @property - def name(self): - return compiled.CompiledContextName(self, self.class_context.name.string_name) - - -class TreeInstance(AbstractInstanceContext): - @property - def name(self): - return filters.ContextName(self, self.class_context.name.tree_name) - @memoize_default() def create_instance_context(self, class_context, node): + if node.parent.type in ('funcdef', 'classdef'): + node = node.parent scope = node.get_parent_scope() if scope == class_context.classdef: return class_context @@ -183,6 +169,28 @@ class TreeInstance(AbstractInstanceContext): raise NotImplementedError return class_context + def __repr__(self): + return "<%s of %s(%s)>" % (self.__class__.__name__, self.class_context, + self.var_args) + + +class CompiledInstance(AbstractInstanceContext): + @property + def name(self): + return compiled.CompiledContextName(self, self.class_context.name.string_name) + + def create_instance_context(self, class_context, node): + if node.get_parent_scope().type == 'classdef': + return class_context + else: + return super(CompiledInstance, self).create_instance_context(class_context, node) + + +class TreeInstance(AbstractInstanceContext): + @property + def name(self): + return filters.ContextName(self, self.class_context.name.tree_name) + class AnonymousInstance(TreeInstance): def __init__(self, evaluator, parent_context, class_context): @@ -194,7 +202,22 @@ class AnonymousInstance(TreeInstance): ) +class CompiledInstanceName(compiled.CompiledName): + def __init__(self, evaluator, instance, parent_context, name): + super(CompiledInstanceName, self).__init__(evaluator, parent_context, name) + self._instance = instance + + def infer(self): + for v in super(CompiledInstanceName, self).infer(): + if isinstance(v, er.FunctionContext): + yield BoundMethod(self._instance, self.parent_context, v) + else: + yield v + + class CompiledInstanceClassFilter(compiled.CompiledObjectFilter): + name_class = CompiledInstanceName + def __init__(self, evaluator, instance, compiled_object): super(CompiledInstanceClassFilter, self).__init__( evaluator, @@ -203,10 +226,8 @@ class CompiledInstanceClassFilter(compiled.CompiledObjectFilter): ) self._instance = instance - def _filter(self, names): - names = super(CompiledInstanceClassFilter, self)._filter(names) - return [get_instance_el(self._evaluator, self._instance, name, True) - for name in names] + def _create(self, name): + return self.name_class(self._evaluator, self._instance, self._compiled_obj, name) class BoundMethod(Context): @@ -252,6 +273,20 @@ class LazyInstanceName(filters.TreeNameDefinition): return self._instance.create_instance_context(self._class_context, self.tree_name) +class LazyInstanceName(filters.TreeNameDefinition): + """ + This name calculates the parent_context lazily. + """ + def __init__(self, instance, class_context, tree_name): + self._instance = instance + self._class_context = class_context + self.tree_name = tree_name + + @property + def parent_context(self): + return self._instance.create_instance_context(self._class_context, self.tree_name) + + class LazyInstanceClassName(LazyInstanceName): def infer(self): for v in super(LazyInstanceClassName, self).infer(): @@ -289,9 +324,6 @@ class InstanceClassFilter(filters.ParserTreeFilter): names = super(InstanceClassFilter, self)._filter(names) return [name for name in names if self._access_possible(name)] - def _check_flows(self, names): - return names - def _convert_names(self, names): return [self.name_class(self.context, self._class_context, name) for name in names] @@ -303,9 +335,10 @@ class SelfNameFilter(InstanceClassFilter): names = self._filter_self_names(names) if isinstance(self._parser_scope, compiled.CompiledObject): # This would be for builtin skeletons, which are not yet supported. - return [] - start, end = self._parser_scope.start_pos, self._parser_scope.end_pos - return [n for n in names if start < n.start_pos < end] + return list(names) + else: + start, end = self._parser_scope.start_pos, self._parser_scope.end_pos + return [n for n in names if start < n.start_pos < end] def _filter_self_names(self, names): for name in names: @@ -323,6 +356,9 @@ class SelfNameFilter(InstanceClassFilter): name = init_execution.name_for_position(name.start_pos) yield name + def _check_flows(self, names): + return names + class ParamArguments(object): """