mirror of
https://github.com/davidhalter/jedi.git
synced 2025-12-07 14:34:31 +08:00
Use names of classes to infer names of instances
This commit is contained in:
@@ -169,7 +169,7 @@ class AbstractInstanceContext(Context):
|
|||||||
|
|
||||||
def create_init_executions(self):
|
def create_init_executions(self):
|
||||||
for name in self.get_function_slot_names(u'__init__'):
|
for name in self.get_function_slot_names(u'__init__'):
|
||||||
if isinstance(name, SelfName):
|
if isinstance(name, LazyInstanceClassName):
|
||||||
function = FunctionContext.from_context(
|
function = FunctionContext.from_context(
|
||||||
self.parent_context,
|
self.parent_context,
|
||||||
name.tree_name.parent
|
name.tree_name.parent
|
||||||
@@ -351,10 +351,15 @@ class SelfName(filters.TreeNameDefinition):
|
|||||||
return self._instance.create_instance_context(self.class_context, self.tree_name)
|
return self._instance.create_instance_context(self.class_context, self.tree_name)
|
||||||
|
|
||||||
|
|
||||||
class LazyInstanceClassName(SelfName):
|
class LazyInstanceClassName(object):
|
||||||
|
def __init__(self, instance, class_context, class_member_name):
|
||||||
|
self._instance = instance
|
||||||
|
self.class_context = class_context
|
||||||
|
self._class_member_name = class_member_name
|
||||||
|
|
||||||
@iterator_to_context_set
|
@iterator_to_context_set
|
||||||
def infer(self):
|
def infer(self):
|
||||||
for result_context in super(LazyInstanceClassName, self).infer():
|
for result_context in self._class_member_name.infer():
|
||||||
if isinstance(result_context, FunctionContext):
|
if isinstance(result_context, 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
|
||||||
@@ -364,12 +369,45 @@ class LazyInstanceClassName(SelfName):
|
|||||||
for c in apply_py__get__(result_context, self._instance):
|
for c in apply_py__get__(result_context, self._instance):
|
||||||
yield c
|
yield c
|
||||||
|
|
||||||
|
def __getattr__(self, name):
|
||||||
|
return getattr(self._class_member_name, name)
|
||||||
|
|
||||||
class InstanceClassFilter(filters.ParserTreeFilter):
|
|
||||||
|
class InstanceClassFilter(filters.AbstractFilter):
|
||||||
|
"""
|
||||||
|
This filter is special in that it uses the class filter and wraps the
|
||||||
|
resulting names in LazyINstanceClassName. The idea is that the class name
|
||||||
|
filtering can be very flexible and always be reflected in instances.
|
||||||
|
"""
|
||||||
name_class = LazyInstanceClassName
|
name_class = LazyInstanceClassName
|
||||||
|
|
||||||
def __init__(self, evaluator, context, class_context, origin_scope):
|
def __init__(self, evaluator, context, class_context, origin_scope):
|
||||||
super(InstanceClassFilter, self).__init__(
|
self._instance = context
|
||||||
|
self._class_context = class_context
|
||||||
|
self._class_filter = next(class_context.get_filters(
|
||||||
|
search_global=False,
|
||||||
|
origin_scope=origin_scope,
|
||||||
|
is_instance=True,
|
||||||
|
))
|
||||||
|
|
||||||
|
def get(self, name):
|
||||||
|
return self._convert(self._class_filter.get(name))
|
||||||
|
|
||||||
|
def values(self):
|
||||||
|
return self._convert(self._class_filter.values())
|
||||||
|
|
||||||
|
def _convert(self, names):
|
||||||
|
return [LazyInstanceClassName(self._instance, self._class_context, n) for n in names]
|
||||||
|
|
||||||
|
|
||||||
|
class SelfAttributeFilter(filters.ParserTreeFilter):
|
||||||
|
"""
|
||||||
|
This class basically filters all the use cases where `self.*` was assigned.
|
||||||
|
"""
|
||||||
|
name_class = SelfName
|
||||||
|
|
||||||
|
def __init__(self, evaluator, context, class_context, origin_scope):
|
||||||
|
super(SelfAttributeFilter, self).__init__(
|
||||||
evaluator=evaluator,
|
evaluator=evaluator,
|
||||||
context=context,
|
context=context,
|
||||||
node_context=class_context,
|
node_context=class_context,
|
||||||
@@ -377,32 +415,6 @@ class InstanceClassFilter(filters.ParserTreeFilter):
|
|||||||
)
|
)
|
||||||
self._class_context = class_context
|
self._class_context = class_context
|
||||||
|
|
||||||
def _equals_origin_scope(self):
|
|
||||||
node = self._origin_scope
|
|
||||||
while node is not None:
|
|
||||||
if node == self._parser_scope or node == self.context:
|
|
||||||
return True
|
|
||||||
node = get_parent_scope(node)
|
|
||||||
return False
|
|
||||||
|
|
||||||
def _access_possible(self, name):
|
|
||||||
return not name.value.startswith('__') or name.value.endswith('__') \
|
|
||||||
or self._equals_origin_scope()
|
|
||||||
|
|
||||||
def _filter(self, names):
|
|
||||||
names = super(InstanceClassFilter, self)._filter(names)
|
|
||||||
return [name for name in names if self._access_possible(name)]
|
|
||||||
|
|
||||||
def _convert_names(self, names):
|
|
||||||
return [self.name_class(self.context, self._class_context, name) for name in names]
|
|
||||||
|
|
||||||
|
|
||||||
class SelfAttributeFilter(InstanceClassFilter):
|
|
||||||
"""
|
|
||||||
This class basically filters all the use cases where `self.*` was assigned.
|
|
||||||
"""
|
|
||||||
name_class = SelfName
|
|
||||||
|
|
||||||
def _filter(self, names):
|
def _filter(self, names):
|
||||||
names = self._filter_self_names(names)
|
names = self._filter_self_names(names)
|
||||||
if isinstance(self._parser_scope, compiled.CompiledObject) and False:
|
if isinstance(self._parser_scope, compiled.CompiledObject) and False:
|
||||||
@@ -421,6 +433,21 @@ class SelfAttributeFilter(InstanceClassFilter):
|
|||||||
if name.is_definition() and self._access_possible(name):
|
if name.is_definition() and self._access_possible(name):
|
||||||
yield name
|
yield name
|
||||||
|
|
||||||
|
def _equals_origin_scope(self):
|
||||||
|
node = self._origin_scope
|
||||||
|
while node is not None:
|
||||||
|
if node == self._parser_scope or node == self.context:
|
||||||
|
return True
|
||||||
|
node = get_parent_scope(node)
|
||||||
|
return False
|
||||||
|
|
||||||
|
def _access_possible(self, name):
|
||||||
|
return not name.value.startswith('__') or name.value.endswith('__') \
|
||||||
|
or self._equals_origin_scope()
|
||||||
|
|
||||||
|
def _convert_names(self, names):
|
||||||
|
return [self.name_class(self.context, self._class_context, name) for name in names]
|
||||||
|
|
||||||
def _check_flows(self, names):
|
def _check_flows(self, names):
|
||||||
return names
|
return names
|
||||||
|
|
||||||
|
|||||||
@@ -59,9 +59,10 @@ def apply_py__get__(context, base_context):
|
|||||||
|
|
||||||
|
|
||||||
class ClassName(TreeNameDefinition):
|
class ClassName(TreeNameDefinition):
|
||||||
def __init__(self, parent_context, tree_name, name_context):
|
def __init__(self, parent_context, tree_name, name_context, apply_decorators):
|
||||||
super(ClassName, self).__init__(parent_context, tree_name)
|
super(ClassName, self).__init__(parent_context, tree_name)
|
||||||
self._name_context = name_context
|
self._name_context = name_context
|
||||||
|
self._apply_decorators = apply_decorators
|
||||||
|
|
||||||
@iterator_to_context_set
|
@iterator_to_context_set
|
||||||
def infer(self):
|
def infer(self):
|
||||||
@@ -73,16 +74,29 @@ class ClassName(TreeNameDefinition):
|
|||||||
self.parent_context.evaluator, self._name_context, self.tree_name)
|
self.parent_context.evaluator, self._name_context, self.tree_name)
|
||||||
|
|
||||||
for result_context in inferred:
|
for result_context in inferred:
|
||||||
for c in apply_py__get__(result_context, self.parent_context):
|
if self._apply_decorators:
|
||||||
yield c
|
for c in apply_py__get__(result_context, self.parent_context):
|
||||||
|
yield c
|
||||||
|
else:
|
||||||
|
yield result_context
|
||||||
|
|
||||||
|
|
||||||
class ClassFilter(ParserTreeFilter):
|
class ClassFilter(ParserTreeFilter):
|
||||||
name_class = ClassName
|
name_class = ClassName
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
self._is_instance = kwargs.pop('is_instance')
|
||||||
|
super(ClassFilter, self).__init__(*args, **kwargs)
|
||||||
|
|
||||||
def _convert_names(self, names):
|
def _convert_names(self, names):
|
||||||
return [self.name_class(self.context, name, self._node_context)
|
return [
|
||||||
for name in names]
|
self.name_class(
|
||||||
|
parent_context=self.context,
|
||||||
|
tree_name=name,
|
||||||
|
name_context=self._node_context,
|
||||||
|
apply_decorators=not self._is_instance,
|
||||||
|
) for name in names
|
||||||
|
]
|
||||||
|
|
||||||
def _equals_origin_scope(self):
|
def _equals_origin_scope(self):
|
||||||
node = self._origin_scope
|
node = self._origin_scope
|
||||||
@@ -182,7 +196,9 @@ class ClassContext(use_metaclass(CachedMetaClass, TreeContext)):
|
|||||||
else:
|
else:
|
||||||
yield ClassFilter(
|
yield ClassFilter(
|
||||||
self.evaluator, self, node_context=cls,
|
self.evaluator, self, node_context=cls,
|
||||||
origin_scope=origin_scope)
|
origin_scope=origin_scope,
|
||||||
|
is_instance=is_instance
|
||||||
|
)
|
||||||
|
|
||||||
def is_class(self):
|
def is_class(self):
|
||||||
return True
|
return True
|
||||||
|
|||||||
Reference in New Issue
Block a user