From afac66d82cc1231852577257b7c8f93cf6e99e51 Mon Sep 17 00:00:00 2001 From: Dave Halter Date: Sun, 6 Nov 2016 18:28:04 +0100 Subject: [PATCH] Working on __init__. --- jedi/evaluate/__init__.py | 15 ++++++-- jedi/evaluate/compiled/__init__.py | 7 ++++ jedi/evaluate/instance.py | 57 +++++++++++++++++++++++++++--- jedi/evaluate/representation.py | 2 +- 4 files changed, 72 insertions(+), 9 deletions(-) diff --git a/jedi/evaluate/__init__.py b/jedi/evaluate/__init__.py index 91fbaef7..526bae33 100644 --- a/jedi/evaluate/__init__.py +++ b/jedi/evaluate/__init__.py @@ -515,15 +515,24 @@ class Evaluator(object): return element def create_context(self, module_context, node): - def from_scope_node(scope_node): + def from_scope_node(scope_node, child_is_funcdef=None): + is_funcdef = scope_node.type == 'funcdef' parent_context = None parent_scope = scope_node.get_parent_scope() if parent_scope is not None: - parent_context = from_scope_node(parent_scope) + parent_context = from_scope_node(parent_scope, child_is_funcdef=is_funcdef) + + # TODO this whole procedure just ignores decorators if scope_node == module_context.module_node: return module_context - elif scope_node.type == 'funcdef': + elif is_funcdef: return er.AnonymousFunctionExecution(self, parent_context, scope_node) + elif scope_node.type == 'classdef': + if child_is_funcdef: + # anonymous instance + raise NotImplementedError + else: + return er.ClassContext(self, scope_node, parent_context) raise DeprecationWarning return self.wrap(scope, parent_context=parent_context) diff --git a/jedi/evaluate/compiled/__init__.py b/jedi/evaluate/compiled/__init__.py index 48886677..afd81516 100644 --- a/jedi/evaluate/compiled/__init__.py +++ b/jedi/evaluate/compiled/__init__.py @@ -258,6 +258,13 @@ class CompiledObject(Context): def get_imports(self): return [] # Builtins don't have imports + @property + def classdef(self): + """ + This is used to be able to work with compiled fakes. + """ + return self + class CompiledName(AbstractNameDefinition): def __init__(self, evaluator, parent_context, name): diff --git a/jedi/evaluate/instance.py b/jedi/evaluate/instance.py index 2be36160..88e2064c 100644 --- a/jedi/evaluate/instance.py +++ b/jedi/evaluate/instance.py @@ -5,6 +5,8 @@ from jedi import debug from jedi.evaluate import compiled from jedi.evaluate.filters import ParserTreeFilter, ContextName, TreeNameDefinition from jedi.evaluate.context import Context +from jedi.evaluate.cache import memoize_default +from jedi.evaluate import representation as er class AbstractInstanceContext(Context): @@ -91,13 +93,13 @@ class AbstractInstanceContext(Context): if isinstance(cls, compiled.CompiledObject): yield SelfNameFilter(self.evaluator, self, cls, origin_scope) else: - yield SelfNameFilter(self.evaluator, self, cls.classdef, origin_scope) + yield SelfNameFilter(self.evaluator, self, cls, origin_scope) for cls in self._class_context.py__mro__(): if isinstance(cls, compiled.CompiledObject): yield CompiledInstanceClassFilter(self.evaluator, self, cls) else: - yield InstanceClassFilter(self.evaluator, self, cls.classdef, origin_scope) + yield InstanceClassFilter(self.evaluator, self, cls, origin_scope) def py__getitem__(self, index): try: @@ -149,6 +151,31 @@ class TreeInstance(AbstractInstanceContext): def name(self): return ContextName(self, self._class_context.name) + @memoize_default() + def create_instance_context(self, class_context, node): + scope = node.get_parent_scope() + if scope == class_context.classdef: + return self + else: + parent_context = self.create_instance_context(class_context, scope) + if scope.type == 'funcdef': + if scope.name.value == '__init__' and parent_context == self: + return er.FunctionExecutionContext( + self.evaluator, + self.parent_context, + scope, + self.var_args + ) + else: + return er.AnonymousFunctionExecution( + self.evaluator, + self.parent_context, + scope, + ) + else: + raise NotImplementedError + return class_context + class CompiledInstanceClassFilter(compiled.CompiledObjectFilter): def __init__(self, evaluator, instance, compiled_object): @@ -190,13 +217,14 @@ class InstanceNameDefinition(TreeNameDefinition): class InstanceClassFilter(ParserTreeFilter): name_class = InstanceNameDefinition - def __init__(self, evaluator, context, parser_scope, origin_scope): + def __init__(self, evaluator, context, class_context, origin_scope): super(InstanceClassFilter, self).__init__( evaluator=evaluator, context=context, - parser_scope=parser_scope, + parser_scope=class_context.classdef, origin_scope=origin_scope ) + self._class_context = class_context def _equals_origin_scope(self): node = self._origin_scope @@ -217,6 +245,9 @@ class InstanceClassFilter(ParserTreeFilter): def _check_flows(self, names): return names + def _convert_names(self, names): + return [LazyInstanceName(self._context, self._class_context, name) for name in names] + class SelfNameFilter(InstanceClassFilter): def _filter(self, names): @@ -234,9 +265,25 @@ class SelfNameFilter(InstanceClassFilter): and len(trailer.children) == 2 \ and trailer.children[0] == '.': if name.is_definition() and self._access_possible(name): - init_execution = self._context._get_init_execution() + yield name + continue + init_execution = self._context.get_init_function() # 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 name + + +class LazyInstanceName(TreeNameDefinition): + """ + This name calculates the parent_context lazily. + """ + def __init__(self, instance, class_context, name): + self._instance = instance + self._class_context = class_context + self.name = name + + @property + def parent_context(self): + return self._instance.create_instance_context(self._class_context, self.name) diff --git a/jedi/evaluate/representation.py b/jedi/evaluate/representation.py index b855a846..bec9ad32 100644 --- a/jedi/evaluate/representation.py +++ b/jedi/evaluate/representation.py @@ -59,7 +59,6 @@ from jedi.evaluate.filters import ParserTreeFilter, FunctionExecutionFilter, \ GlobalNameFilter, DictFilter, ContextName from jedi.evaluate.dynamic import search_params from jedi.evaluate import context -from jedi.evaluate.instance import TreeInstance class Executed(context.TreeContext): @@ -468,6 +467,7 @@ class ClassContext(use_metaclass(CachedMetaClass, context.TreeContext, Wrapper)) return [context.LazyKnownContext(compiled.create(self.evaluator, object))] def py__call__(self, params): + from jedi.evaluate.instance import TreeInstance return set([TreeInstance(self.evaluator, self.parent_context, self, params)]) def py__class__(self):