forked from VimPlug/jedi
Refactor the descriptor logic.
This commit is contained in:
@@ -508,6 +508,7 @@ def _parse_function_doc(doc):
|
|||||||
|
|
||||||
def _create_from_name(evaluator, module, compiled_object, name):
|
def _create_from_name(evaluator, module, compiled_object, name):
|
||||||
obj = compiled_object.obj
|
obj = compiled_object.obj
|
||||||
|
faked = None
|
||||||
try:
|
try:
|
||||||
faked = fake.get_faked(evaluator, module, obj, parent_context=compiled_object, name=name)
|
faked = fake.get_faked(evaluator, module, obj, parent_context=compiled_object, name=name)
|
||||||
if faked.type == 'funcdef':
|
if faked.type == 'funcdef':
|
||||||
@@ -523,7 +524,7 @@ def _create_from_name(evaluator, module, compiled_object, name):
|
|||||||
# PyQt4.QtGui.QStyleOptionComboBox.currentText
|
# PyQt4.QtGui.QStyleOptionComboBox.currentText
|
||||||
# -> just set it to None
|
# -> just set it to None
|
||||||
obj = None
|
obj = None
|
||||||
return create(evaluator, obj, parent_context=compiled_object)
|
return create(evaluator, obj, parent_context=compiled_object, faked=faked)
|
||||||
|
|
||||||
|
|
||||||
def builtin_from_name(evaluator, string):
|
def builtin_from_name(evaluator, string):
|
||||||
@@ -558,21 +559,17 @@ def compiled_objects_cache(attribute_name):
|
|||||||
Caching the id has the advantage that an object doesn't need to be
|
Caching the id has the advantage that an object doesn't need to be
|
||||||
hashable.
|
hashable.
|
||||||
"""
|
"""
|
||||||
def wrapper(evaluator, obj, parent_context=None, module=None):
|
def wrapper(evaluator, obj, parent_context=None, module=None, faked=None):
|
||||||
cache = getattr(evaluator, attribute_name)
|
cache = getattr(evaluator, attribute_name)
|
||||||
# Do a very cheap form of caching here.
|
# Do a very cheap form of caching here.
|
||||||
key = id(obj), id(parent_context)
|
key = id(obj), id(parent_context)
|
||||||
try:
|
try:
|
||||||
return cache[key][0]
|
return cache[key][0]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
# TODO this whole decorator looks way too ugly and this if
|
# TODO this whole decorator is way too ugly
|
||||||
# doesn't make it better. Find a more generic solution.
|
result = func(evaluator, obj, parent_context, module, faked)
|
||||||
if parent_context or module:
|
|
||||||
result = func(evaluator, obj, parent_context, module)
|
|
||||||
else:
|
|
||||||
result = func(evaluator, obj)
|
|
||||||
# Need to cache all of them, otherwise the id could be overwritten.
|
# Need to cache all of them, otherwise the id could be overwritten.
|
||||||
cache[key] = result, obj, parent_context, module
|
cache[key] = result, obj, parent_context, module, faked
|
||||||
return result
|
return result
|
||||||
return wrapper
|
return wrapper
|
||||||
|
|
||||||
@@ -580,12 +577,11 @@ def compiled_objects_cache(attribute_name):
|
|||||||
|
|
||||||
|
|
||||||
@compiled_objects_cache('compiled_cache')
|
@compiled_objects_cache('compiled_cache')
|
||||||
def create(evaluator, obj, parent_context=None, module=None):
|
def create(evaluator, obj, parent_context=None, module=None, faked=None):
|
||||||
"""
|
"""
|
||||||
A very weird interface class to this module. The more options provided the
|
A very weird interface class to this module. The more options provided the
|
||||||
more acurate loading compiled objects is.
|
more acurate loading compiled objects is.
|
||||||
"""
|
"""
|
||||||
faked = None
|
|
||||||
if inspect.ismodule(obj):
|
if inspect.ismodule(obj):
|
||||||
if parent_context is not None:
|
if parent_context is not None:
|
||||||
# Modules don't have parents, be careful with caching: recurse.
|
# Modules don't have parents, be careful with caching: recurse.
|
||||||
|
|||||||
+2
-23
@@ -266,6 +266,7 @@ class NameFinder(object):
|
|||||||
for filter in filters:
|
for filter in filters:
|
||||||
names = filter.get(self._name)
|
names = filter.get(self._name)
|
||||||
if names:
|
if names:
|
||||||
|
self._last_used_filter = filter
|
||||||
break
|
break
|
||||||
debug.dbg('finder.filter_name "%s" in (%s): %s@%s', self._string_name,
|
debug.dbg('finder.filter_name "%s" in (%s): %s@%s', self._string_name,
|
||||||
self._context, names, self._position)
|
self._context, names, self._position)
|
||||||
@@ -310,13 +311,7 @@ class NameFinder(object):
|
|||||||
def _names_to_types(self, names, attribute_lookup):
|
def _names_to_types(self, names, attribute_lookup):
|
||||||
types = set()
|
types = set()
|
||||||
|
|
||||||
for name in names:
|
types = unite(name.infer() for name in names)
|
||||||
new_types = name.infer()
|
|
||||||
if isinstance(self._context, (er.ClassContext, AbstractInstanceContext)) \
|
|
||||||
and attribute_lookup:
|
|
||||||
types |= set(self._resolve_descriptors(name, new_types))
|
|
||||||
else:
|
|
||||||
types |= set(new_types)
|
|
||||||
|
|
||||||
debug.dbg('finder._names_to_types: %s -> %s', names, types)
|
debug.dbg('finder._names_to_types: %s -> %s', names, types)
|
||||||
if not names and isinstance(self._context, AbstractInstanceContext):
|
if not names and isinstance(self._context, AbstractInstanceContext):
|
||||||
@@ -338,22 +333,6 @@ class NameFinder(object):
|
|||||||
break
|
break
|
||||||
return types
|
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
|
|
||||||
|
|
||||||
result = set()
|
|
||||||
for r in types:
|
|
||||||
try:
|
|
||||||
desc_return = r.get_descriptor_returns
|
|
||||||
except AttributeError:
|
|
||||||
result.add(r)
|
|
||||||
else:
|
|
||||||
result |= desc_return(self._context)
|
|
||||||
return result
|
|
||||||
|
|
||||||
|
|
||||||
def _name_to_types(evaluator, context, name):
|
def _name_to_types(evaluator, context, name):
|
||||||
types = []
|
types = []
|
||||||
|
|||||||
@@ -62,8 +62,7 @@ class AbstractInstanceContext(Context):
|
|||||||
for name in names
|
for name in names
|
||||||
)
|
)
|
||||||
|
|
||||||
def get_descriptor_returns(self, obj):
|
def py__get__(self, obj):
|
||||||
""" Throws a KeyError if there's no method. """
|
|
||||||
# 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('__get__')
|
names = self.get_function_slot_names('__get__')
|
||||||
@@ -277,21 +276,22 @@ class LazyInstanceName(filters.TreeNameDefinition):
|
|||||||
|
|
||||||
class LazyInstanceClassName(LazyInstanceName):
|
class LazyInstanceClassName(LazyInstanceName):
|
||||||
def infer(self):
|
def infer(self):
|
||||||
for v in super(LazyInstanceClassName, self).infer():
|
for result_context in super(LazyInstanceClassName, self).infer():
|
||||||
if isinstance(v, er.FunctionContext):
|
if isinstance(result_context, er.FunctionContext):
|
||||||
# Classes are never used to resolve anything within the
|
# Classes are never used to resolve anything within the
|
||||||
# functions. Only other functions and modules will resolve
|
# functions. Only other functions and modules will resolve
|
||||||
# those things.
|
# those things.
|
||||||
parent_context = v.parent_context
|
parent_context = result_context.parent_context
|
||||||
while isinstance(parent_context, er.ClassContext):
|
while isinstance(parent_context, er.ClassContext):
|
||||||
parent_context = parent_context.parent_context
|
parent_context = parent_context.parent_context
|
||||||
|
|
||||||
yield BoundMethod(
|
yield BoundMethod(
|
||||||
v.evaluator, self._instance, self.class_context,
|
result_context.evaluator, self._instance, self.class_context,
|
||||||
parent_context, v.funcdef
|
parent_context, result_context.funcdef
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
yield v
|
for c in er.apply_py__get__(result_context, self._instance):
|
||||||
|
yield c
|
||||||
|
|
||||||
|
|
||||||
class InstanceClassFilter(filters.ParserTreeFilter):
|
class InstanceClassFilter(filters.ParserTreeFilter):
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ from jedi.evaluate import imports
|
|||||||
from jedi.evaluate import helpers
|
from jedi.evaluate import helpers
|
||||||
from jedi.evaluate.filters import ParserTreeFilter, FunctionExecutionFilter, \
|
from jedi.evaluate.filters import ParserTreeFilter, FunctionExecutionFilter, \
|
||||||
GlobalNameFilter, DictFilter, ContextName, AbstractNameDefinition, \
|
GlobalNameFilter, DictFilter, ContextName, AbstractNameDefinition, \
|
||||||
ParamName, AnonymousInstanceParamName
|
ParamName, AnonymousInstanceParamName, TreeNameDefinition
|
||||||
from jedi.evaluate.dynamic import search_params
|
from jedi.evaluate.dynamic import search_params
|
||||||
from jedi.evaluate import context
|
from jedi.evaluate import context
|
||||||
|
|
||||||
@@ -74,6 +74,27 @@ class Executed(context.TreeContext):
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def apply_py__get__(context, base_context):
|
||||||
|
try:
|
||||||
|
method = context.py__get__
|
||||||
|
except AttributeError:
|
||||||
|
yield context
|
||||||
|
else:
|
||||||
|
for descriptor_context in method(base_context):
|
||||||
|
yield descriptor_context
|
||||||
|
|
||||||
|
|
||||||
|
class ClassName(TreeNameDefinition):
|
||||||
|
def infer(self):
|
||||||
|
for result_context in super(ClassName, self).infer():
|
||||||
|
for c in apply_py__get__(result_context, self.parent_context):
|
||||||
|
yield c
|
||||||
|
|
||||||
|
|
||||||
|
class ClassFilter(ParserTreeFilter):
|
||||||
|
name_class = ClassName
|
||||||
|
|
||||||
|
|
||||||
class ClassContext(use_metaclass(CachedMetaClass, context.TreeContext)):
|
class ClassContext(use_metaclass(CachedMetaClass, context.TreeContext)):
|
||||||
"""
|
"""
|
||||||
This class is not only important to extend `tree.Class`, it is also a
|
This class is not only important to extend `tree.Class`, it is also a
|
||||||
@@ -164,7 +185,7 @@ class ClassContext(use_metaclass(CachedMetaClass, context.TreeContext)):
|
|||||||
for filter in scope.get_filters(is_instance=is_instance):
|
for filter in scope.get_filters(is_instance=is_instance):
|
||||||
yield filter
|
yield filter
|
||||||
else:
|
else:
|
||||||
yield ParserTreeFilter(self.evaluator, self, scope.classdef, origin_scope=origin_scope)
|
yield ClassFilter(self.evaluator, self, scope.classdef, origin_scope=origin_scope)
|
||||||
|
|
||||||
def is_class(self):
|
def is_class(self):
|
||||||
return True
|
return True
|
||||||
|
|||||||
Reference in New Issue
Block a user