1
0
forked from VimPlug/jedi

Refactor py__get__ support pretty heavily

This commit is contained in:
Dave Halter
2018-11-01 19:09:07 +01:00
parent 52aa5b6764
commit fbc327b960
7 changed files with 38 additions and 37 deletions

View File

@@ -53,6 +53,13 @@ class FunctionMixin(object):
for filter in scope.get_filters(search_global=False, origin_scope=origin_scope): for filter in scope.get_filters(search_global=False, origin_scope=origin_scope):
yield filter yield filter
def py__get__(self, instance, class_context):
from jedi.evaluate.context.instance import BoundMethod
if instance is None:
# Calling the Foo.bar results in the original bar function.
return ContextSet([self])
return ContextSet([BoundMethod(instance, class_context, self)])
def get_param_names(self): def get_param_names(self):
function_execution = self.get_function_execution() function_execution = self.get_function_execution()
return [ParamName(function_execution, param.name) return [ParamName(function_execution, param.name)
@@ -335,7 +342,7 @@ class FunctionExecutionContext(TreeContext):
return self.get_return_values() return self.get_return_values()
class OverloadedFunctionContext(ContextWrapper): class OverloadedFunctionContext(FunctionMixin, ContextWrapper):
def __init__(self, function, overloaded_functions): def __init__(self, function, overloaded_functions):
super(OverloadedFunctionContext, self).__init__(function) super(OverloadedFunctionContext, self).__init__(function)
self.overloaded_functions = overloaded_functions self.overloaded_functions = overloaded_functions

View File

@@ -8,7 +8,7 @@ from jedi.evaluate.base_context import Context, NO_CONTEXTS, ContextSet, \
iterator_to_context_set, ContextWrapper iterator_to_context_set, ContextWrapper
from jedi.evaluate.lazy_context import LazyKnownContext, LazyKnownContexts from jedi.evaluate.lazy_context import LazyKnownContext, LazyKnownContexts
from jedi.evaluate.cache import evaluator_method_cache from jedi.evaluate.cache import evaluator_method_cache
from jedi.evaluate.arguments import AbstractArguments, AnonymousArguments, \ from jedi.evaluate.arguments import AnonymousArguments, \
ValuesArguments, TreeArgumentsWrapper ValuesArguments, TreeArgumentsWrapper
from jedi.evaluate.context.function import FunctionExecutionContext, \ from jedi.evaluate.context.function import FunctionExecutionContext, \
FunctionContext, FunctionMixin, OverloadedFunctionContext, MethodContext FunctionContext, FunctionMixin, OverloadedFunctionContext, MethodContext
@@ -109,16 +109,17 @@ class AbstractInstanceContext(Context):
for name in names for name in names
) )
def py__get__(self, obj): def py__get__(self, obj, class_context):
"""
obj may be None.
"""
# Arguments in __get__ descriptors are obj, class. # Arguments in __get__ descriptors are obj, class.
# `method` is the new parent of the array, don't know if that's good. # `method` is the new parent of the array, don't know if that's good.
names = self.get_function_slot_names(u'__get__') names = self.get_function_slot_names(u'__get__')
if names: if names:
if obj.is_instance(): if obj is None:
return self.execute_function_slots(names, obj, obj.class_context) obj = compiled.builtin_from_name(self.evaluator, u'None')
else: return self.execute_function_slots(names, obj, class_context)
none_obj = compiled.builtin_from_name(self.evaluator, u'None')
return self.execute_function_slots(names, none_obj, obj)
else: else:
return ContextSet([self]) return ContextSet([self])
@@ -273,8 +274,10 @@ class TreeInstance(AbstractInstanceContext):
# Just take the first result, it should always be one, because we # Just take the first result, it should always be one, because we
# control the typeshed code. # control the typeshed code.
c = self.class_context c = self.class_context
if isinstance(func, MethodContext): try:
c = func.class_context c = func.class_context
except AttributeError:
pass
bound = BoundMethod(self, c, func) bound = BoundMethod(self, c, func)
execution = bound.get_function_execution(self.var_args) execution = bound.get_function_execution(self.var_args)
if not execution.matches_signature(): if not execution.matches_signature():
@@ -442,14 +445,8 @@ class LazyInstanceClassName(object):
@iterator_to_context_set @iterator_to_context_set
def infer(self): def infer(self):
for result_context in self._class_member_name.infer(): for result_context in self._class_member_name.infer():
if isinstance(result_context, (FunctionContext, OverloadedFunctionContext)): for c in apply_py__get__(result_context, self._instance, self.class_context):
# Classes are never used to resolve anything within the yield c
# functions. Only other functions and modules will resolve
# those things.
yield BoundMethod(self._instance, self.class_context, result_context)
else:
for c in apply_py__get__(result_context, self._instance):
yield c
def __getattr__(self, name): def __getattr__(self, name):
return getattr(self._class_member_name, name) return getattr(self._class_member_name, name)

View File

@@ -50,13 +50,13 @@ from jedi.evaluate.base_context import ContextSet, iterator_to_context_set, \
TreeContext, NO_CONTEXTS TreeContext, NO_CONTEXTS
def apply_py__get__(context, base_context): def apply_py__get__(context, instance, class_context):
try: try:
method = context.py__get__ method = context.py__get__
except AttributeError: except AttributeError:
yield context yield context
else: else:
for descriptor_context in method(base_context): for descriptor_context in method(instance, class_context):
yield descriptor_context yield descriptor_context
@@ -122,7 +122,9 @@ class ClassName(TreeNameDefinition):
for result_context in inferred: for result_context in inferred:
if self._apply_decorators: if self._apply_decorators:
for c in apply_py__get__(result_context, self.parent_context): for c in apply_py__get__(result_context,
instance=None,
class_context=self.parent_context):
yield c yield c
else: else:
yield result_context yield result_context

View File

@@ -404,7 +404,7 @@ def import_module(evaluator, import_names, parent_module_context, sys_path):
import_names=import_names, import_names=import_names,
sys_path=sys_path, sys_path=sys_path,
) )
return ContextSet(module) return ContextSet([module])
module_name = '.'.join(import_names) module_name = '.'.join(import_names)
if parent_module_context is None: if parent_module_context is None:

View File

@@ -284,8 +284,7 @@ class StaticMethodObject(AbstractObjectOverwrite, ContextWrapper):
def get_object(self): def get_object(self):
return self._wrapped_context return self._wrapped_context
@publish_method('__get__') def py__get__(self, instance, klass):
def _py__get__(self):
return ContextSet([self._wrapped_context]) return ContextSet([self._wrapped_context])
@@ -302,12 +301,11 @@ class ClassMethodObject(AbstractObjectOverwrite, ContextWrapper):
def get_object(self): def get_object(self):
return self._wrapped_context return self._wrapped_context
def py__get__(self, obj): def py__get__(self, obj, class_context):
actual, = self._wrapped_context.py__getattribute__('__get__') return ContextSet([
klass = obj ClassMethodGet(__get__, class_context, self._function)
if not obj.is_class(): for __get__ in self._wrapped_context.py__getattribute__('__get__')
klass = obj.py__class__() ])
return ContextSet([ClassMethodGet(actual, klass, self._function)])
class ClassMethodGet(AbstractObjectOverwrite, ContextWrapper): class ClassMethodGet(AbstractObjectOverwrite, ContextWrapper):

View File

@@ -1,8 +1,7 @@
import os import os
from jedi.plugins import typeshed from jedi.plugins import typeshed
from jedi.evaluate.context import TreeInstance, BoundMethod, \ from jedi.evaluate.context import TreeInstance, BoundMethod
ClassContext
from parso.utils import PythonVersionInfo from parso.utils import PythonVersionInfo
from jedi.evaluate.filters import TreeNameDefinition from jedi.evaluate.filters import TreeNameDefinition
@@ -48,7 +47,7 @@ def test_function(Script):
def_, = Script(code + '()').goto_definitions() def_, = Script(code + '()').goto_definitions()
context = def_._name._context context = def_._name._context
assert isinstance(context, TreeInstance) assert isinstance(context, TreeInstance)
assert isinstance(context.class_context, ClassContext), context assert isinstance(context.class_context, typeshed.StubOnlyClass), context
def_, = Script('import threading; threading.Thread').goto_definitions() def_, = Script('import threading; threading.Thread').goto_definitions()
assert isinstance(def_._name._context, typeshed.StubClassContext), def_ assert isinstance(def_._name._context, typeshed.StubClassContext), def_
@@ -86,7 +85,7 @@ def test_method(Script):
def_, = Script(code).goto_definitions() def_, = Script(code).goto_definitions()
context = def_._name._context context = def_._name._context
assert isinstance(context, BoundMethod), context assert isinstance(context, BoundMethod), context
assert isinstance(context._function, typeshed.StubFunctionContext), context assert isinstance(context._wrapped_context, typeshed.StubFunctionContext), context
def_, = Script(code + '()').goto_definitions() def_, = Script(code + '()').goto_definitions()
context = def_._name._context context = def_._name._context

View File

@@ -3,8 +3,7 @@ import pytest
from jedi import settings from jedi import settings
from jedi.evaluate.filters import ContextName from jedi.evaluate.filters import ContextName
from jedi.evaluate.compiled import CompiledContextName from jedi.evaluate.compiled import CompiledContextName
from jedi.plugins.typeshed import StubContextWithCompiled from jedi.plugins.typeshed import StubOnlyModuleContext
from jedi.evaluate.context import FunctionContext
@pytest.fixture() @pytest.fixture()
@@ -16,8 +15,7 @@ def test_base_auto_import_modules(auto_import_json, Script):
loads, = Script('import json; json.loads').goto_definitions() loads, = Script('import json; json.loads').goto_definitions()
assert isinstance(loads._name, ContextName) assert isinstance(loads._name, ContextName)
context, = loads._name.infer() context, = loads._name.infer()
assert isinstance(context, StubContextWithCompiled) assert isinstance(context.parent_context, StubOnlyModuleContext)
assert isinstance(context._wrapped_context, FunctionContext)
def test_auto_import_modules_imports(auto_import_json, Script): def test_auto_import_modules_imports(auto_import_json, Script):