forked from VimPlug/jedi
Refactor AnonymousInstance/TreeInstance, so that the anonymous instance doesn't have to use arguments
This commit is contained in:
@@ -103,12 +103,11 @@ class MethodExecutionContext(FunctionExecutionContext):
|
|||||||
class AbstractInstanceValue(Value):
|
class AbstractInstanceValue(Value):
|
||||||
api_type = u'instance'
|
api_type = u'instance'
|
||||||
|
|
||||||
def __init__(self, inference_state, parent_context, class_value, arguments):
|
def __init__(self, inference_state, parent_context, class_value):
|
||||||
super(AbstractInstanceValue, self).__init__(inference_state, parent_context)
|
super(AbstractInstanceValue, self).__init__(inference_state, parent_context)
|
||||||
# Generated instances are classes that are just generated by self
|
# Generated instances are classes that are just generated by self
|
||||||
# (No arguments) used.
|
# (No arguments) used.
|
||||||
self.class_value = class_value
|
self.class_value = class_value
|
||||||
self.arguments = arguments
|
|
||||||
|
|
||||||
def is_instance(self):
|
def is_instance(self):
|
||||||
return True
|
return True
|
||||||
@@ -135,14 +134,14 @@ class AbstractInstanceValue(Value):
|
|||||||
return [s.bind(self) for s in call_funcs.get_signatures()]
|
return [s.bind(self) for s in call_funcs.get_signatures()]
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "<%s of %s(%s)>" % (self.__class__.__name__, self.class_value)
|
return "<%s of %s>" % (self.__class__.__name__, self.class_value)
|
||||||
|
|
||||||
|
|
||||||
class CompiledInstance(AbstractInstanceValue):
|
class CompiledInstance(AbstractInstanceValue):
|
||||||
def __init__(self, inference_state, parent_context, class_value, arguments):
|
def __init__(self, inference_state, parent_context, class_value, arguments):
|
||||||
self._original_arguments = arguments
|
|
||||||
super(CompiledInstance, self).__init__(inference_state, parent_context,
|
super(CompiledInstance, self).__init__(inference_state, parent_context,
|
||||||
class_value, arguments)
|
class_value)
|
||||||
|
self.arguments = arguments
|
||||||
|
|
||||||
def get_filters(self, origin_scope=None, include_self_names=True):
|
def get_filters(self, origin_scope=None, include_self_names=True):
|
||||||
class_value = self.get_annotated_class_object()
|
class_value = self.get_annotated_class_object()
|
||||||
@@ -158,7 +157,7 @@ class CompiledInstance(AbstractInstanceValue):
|
|||||||
return compiled.CompiledValueName(self, self.class_value.name.string_name)
|
return compiled.CompiledValueName(self, self.class_value.name.string_name)
|
||||||
|
|
||||||
def get_first_non_keyword_argument_values(self):
|
def get_first_non_keyword_argument_values(self):
|
||||||
key, lazy_value = next(self._original_arguments.unpack(), ('', None))
|
key, lazy_value = next(self.arguments.unpack(), ('', None))
|
||||||
if key is not None:
|
if key is not None:
|
||||||
return NO_VALUES
|
return NO_VALUES
|
||||||
|
|
||||||
@@ -168,20 +167,7 @@ class CompiledInstance(AbstractInstanceValue):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
class TreeInstance(AbstractInstanceValue):
|
class _BaseTreeInstance(AbstractInstanceValue):
|
||||||
def __init__(self, inference_state, parent_context, class_value, arguments):
|
|
||||||
# I don't think that dynamic append lookups should happen here. That
|
|
||||||
# sounds more like something that should go to py__iter__.
|
|
||||||
if class_value.py__name__() in ['list', 'set'] \
|
|
||||||
and parent_context.get_root_context().is_builtins_module():
|
|
||||||
# compare the module path with the builtin name.
|
|
||||||
if settings.dynamic_array_additions:
|
|
||||||
arguments = get_dynamic_array_instance(self, arguments)
|
|
||||||
|
|
||||||
super(TreeInstance, self).__init__(inference_state, parent_context,
|
|
||||||
class_value, arguments)
|
|
||||||
self.tree_node = class_value.tree_node
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def array_type(self):
|
def array_type(self):
|
||||||
name = self.class_value.py__name__()
|
name = self.class_value.py__name__()
|
||||||
@@ -194,35 +180,6 @@ class TreeInstance(AbstractInstanceValue):
|
|||||||
def name(self):
|
def name(self):
|
||||||
return ValueName(self, self.class_value.name.tree_name)
|
return ValueName(self, self.class_value.name.tree_name)
|
||||||
|
|
||||||
# This can recurse, if the initialization of the class includes a reference
|
|
||||||
# to itself.
|
|
||||||
@inference_state_method_cache(default=None)
|
|
||||||
def _get_annotated_class_object(self):
|
|
||||||
from jedi.inference.gradual.annotation import py__annotations__, \
|
|
||||||
infer_type_vars_for_execution
|
|
||||||
|
|
||||||
args = InstanceArguments(self, self.arguments)
|
|
||||||
for signature in self.class_value.py__getattribute__('__init__').get_signatures():
|
|
||||||
# Just take the first result, it should always be one, because we
|
|
||||||
# control the typeshed code.
|
|
||||||
if not signature.matches_signature(args):
|
|
||||||
# First check if the signature even matches, if not we don't
|
|
||||||
# need to infer anything.
|
|
||||||
continue
|
|
||||||
bound_method = BoundMethod(self, signature.value)
|
|
||||||
all_annotations = py__annotations__(signature.value.tree_node)
|
|
||||||
type_var_dict = infer_type_vars_for_execution(bound_method, args, all_annotations)
|
|
||||||
if type_var_dict:
|
|
||||||
defined, = self.class_value.define_generics(
|
|
||||||
infer_type_vars_for_execution(signature.value, args, all_annotations),
|
|
||||||
)
|
|
||||||
debug.dbg('Inferred instance value as %s', defined, color='BLUE')
|
|
||||||
return defined
|
|
||||||
return None
|
|
||||||
|
|
||||||
def get_annotated_class_object(self):
|
|
||||||
return self._get_annotated_class_object() or self.class_value
|
|
||||||
|
|
||||||
def get_filters(self, origin_scope=None, include_self_names=True):
|
def get_filters(self, origin_scope=None, include_self_names=True):
|
||||||
class_value = self.get_annotated_class_object()
|
class_value = self.get_annotated_class_object()
|
||||||
if include_self_names:
|
if include_self_names:
|
||||||
@@ -254,6 +211,38 @@ class TreeInstance(AbstractInstanceValue):
|
|||||||
for signature in init.get_signatures():
|
for signature in init.get_signatures():
|
||||||
yield signature.value
|
yield signature.value
|
||||||
|
|
||||||
|
@inference_state_method_cache()
|
||||||
|
def create_instance_context(self, class_context, node):
|
||||||
|
if node.parent.type in ('funcdef', 'classdef'):
|
||||||
|
node = node.parent
|
||||||
|
scope = get_parent_scope(node)
|
||||||
|
if scope == class_context.tree_node:
|
||||||
|
return class_context
|
||||||
|
else:
|
||||||
|
parent_context = self.create_instance_context(class_context, scope)
|
||||||
|
if scope.type == 'funcdef':
|
||||||
|
func = FunctionValue.from_context(
|
||||||
|
parent_context,
|
||||||
|
scope,
|
||||||
|
)
|
||||||
|
bound_method = BoundMethod(self, func)
|
||||||
|
if scope.name.value == '__init__' and parent_context == class_context:
|
||||||
|
if hasattr(self, 'arguments'):
|
||||||
|
return bound_method.as_context(self.arguments)
|
||||||
|
else:
|
||||||
|
return bound_method.as_context()
|
||||||
|
else:
|
||||||
|
return bound_method.as_context()
|
||||||
|
elif scope.type == 'classdef':
|
||||||
|
class_context = ClassValue(self.inference_state, parent_context, scope)
|
||||||
|
return class_context.as_context()
|
||||||
|
elif scope.type in ('comp_for', 'sync_comp_for'):
|
||||||
|
# Comprehensions currently don't have a special scope in Jedi.
|
||||||
|
return self.create_instance_context(class_context, scope)
|
||||||
|
else:
|
||||||
|
raise NotImplementedError
|
||||||
|
return class_context
|
||||||
|
|
||||||
def py__getattribute__alternatives(self, string_name):
|
def py__getattribute__alternatives(self, string_name):
|
||||||
'''
|
'''
|
||||||
Since nothing was inferred, now check the __getattr__ and
|
Since nothing was inferred, now check the __getattr__ and
|
||||||
@@ -276,29 +265,6 @@ class TreeInstance(AbstractInstanceValue):
|
|||||||
self.get_function_slot_names(u'__getattribute__'))
|
self.get_function_slot_names(u'__getattribute__'))
|
||||||
return self.execute_function_slots(names, name)
|
return self.execute_function_slots(names, name)
|
||||||
|
|
||||||
def py__simple_getitem__(self, index):
|
|
||||||
if self.array_type == 'dict':
|
|
||||||
# Logic for dict({'foo': bar}) and dict(foo=bar)
|
|
||||||
# reversed, because:
|
|
||||||
# >>> dict({'a': 1}, a=3)
|
|
||||||
# {'a': 3}
|
|
||||||
# TODO tuple initializations
|
|
||||||
# >>> dict([('a', 4)])
|
|
||||||
# {'a': 4}
|
|
||||||
for key, lazy_context in reversed(list(self.arguments.unpack())):
|
|
||||||
if key is None:
|
|
||||||
values = ValueSet.from_sets(
|
|
||||||
dct_value.py__simple_getitem__(index)
|
|
||||||
for dct_value in lazy_context.infer()
|
|
||||||
if dct_value.array_type == 'dict'
|
|
||||||
)
|
|
||||||
if values:
|
|
||||||
return values
|
|
||||||
else:
|
|
||||||
if key == index:
|
|
||||||
return lazy_context.infer()
|
|
||||||
return super(TreeInstance, self).py__simple_getitem__(index)
|
|
||||||
|
|
||||||
def py__getitem__(self, index_value_set, contextualized_node):
|
def py__getitem__(self, index_value_set, contextualized_node):
|
||||||
names = self.get_function_slot_names(u'__getitem__')
|
names = self.get_function_slot_names(u'__getitem__')
|
||||||
if not names:
|
if not names:
|
||||||
@@ -373,55 +339,84 @@ class TreeInstance(AbstractInstanceValue):
|
|||||||
for name in names
|
for name in names
|
||||||
)
|
)
|
||||||
|
|
||||||
@inference_state_method_cache()
|
|
||||||
def create_instance_context(self, class_context, node):
|
class TreeInstance(_BaseTreeInstance):
|
||||||
if node.parent.type in ('funcdef', 'classdef'):
|
def __init__(self, inference_state, parent_context, class_value, arguments):
|
||||||
node = node.parent
|
# I don't think that dynamic append lookups should happen here. That
|
||||||
scope = get_parent_scope(node)
|
# sounds more like something that should go to py__iter__.
|
||||||
if scope == class_context.tree_node:
|
if class_value.py__name__() in ['list', 'set'] \
|
||||||
return class_context
|
and parent_context.get_root_context().is_builtins_module():
|
||||||
else:
|
# compare the module path with the builtin name.
|
||||||
parent_context = self.create_instance_context(class_context, scope)
|
if settings.dynamic_array_additions:
|
||||||
if scope.type == 'funcdef':
|
arguments = get_dynamic_array_instance(self, arguments)
|
||||||
func = FunctionValue.from_context(
|
|
||||||
parent_context,
|
super(_BaseTreeInstance, self).__init__(inference_state, parent_context,
|
||||||
scope,
|
class_value)
|
||||||
|
self.arguments = arguments
|
||||||
|
self.tree_node = class_value.tree_node
|
||||||
|
|
||||||
|
# This can recurse, if the initialization of the class includes a reference
|
||||||
|
# to itself.
|
||||||
|
@inference_state_method_cache(default=None)
|
||||||
|
def _get_annotated_class_object(self):
|
||||||
|
from jedi.inference.gradual.annotation import py__annotations__, \
|
||||||
|
infer_type_vars_for_execution
|
||||||
|
|
||||||
|
args = InstanceArguments(self, self.arguments)
|
||||||
|
for signature in self.class_value.py__getattribute__('__init__').get_signatures():
|
||||||
|
# Just take the first result, it should always be one, because we
|
||||||
|
# control the typeshed code.
|
||||||
|
if not signature.matches_signature(args):
|
||||||
|
# First check if the signature even matches, if not we don't
|
||||||
|
# need to infer anything.
|
||||||
|
continue
|
||||||
|
bound_method = BoundMethod(self, signature.value)
|
||||||
|
all_annotations = py__annotations__(signature.value.tree_node)
|
||||||
|
type_var_dict = infer_type_vars_for_execution(bound_method, args, all_annotations)
|
||||||
|
if type_var_dict:
|
||||||
|
defined, = self.class_value.define_generics(
|
||||||
|
infer_type_vars_for_execution(signature.value, args, all_annotations),
|
||||||
)
|
)
|
||||||
bound_method = BoundMethod(self, func)
|
debug.dbg('Inferred instance value as %s', defined, color='BLUE')
|
||||||
if scope.name.value == '__init__' and parent_context == class_context:
|
return defined
|
||||||
return bound_method.as_context(self.arguments)
|
return None
|
||||||
|
|
||||||
|
def get_annotated_class_object(self):
|
||||||
|
return self._get_annotated_class_object() or self.class_value
|
||||||
|
|
||||||
|
def py__simple_getitem__(self, index):
|
||||||
|
if self.array_type == 'dict':
|
||||||
|
# Logic for dict({'foo': bar}) and dict(foo=bar)
|
||||||
|
# reversed, because:
|
||||||
|
# >>> dict({'a': 1}, a=3)
|
||||||
|
# {'a': 3}
|
||||||
|
# TODO tuple initializations
|
||||||
|
# >>> dict([('a', 4)])
|
||||||
|
# {'a': 4}
|
||||||
|
for key, lazy_context in reversed(list(self.arguments.unpack())):
|
||||||
|
if key is None:
|
||||||
|
values = ValueSet.from_sets(
|
||||||
|
dct_value.py__simple_getitem__(index)
|
||||||
|
for dct_value in lazy_context.infer()
|
||||||
|
if dct_value.array_type == 'dict'
|
||||||
|
)
|
||||||
|
if values:
|
||||||
|
return values
|
||||||
else:
|
else:
|
||||||
return bound_method.as_context()
|
if key == index:
|
||||||
elif scope.type == 'classdef':
|
return lazy_context.infer()
|
||||||
class_context = ClassValue(self.inference_state, parent_context, scope)
|
return super(TreeInstance, self).py__simple_getitem__(index)
|
||||||
return class_context.as_context()
|
|
||||||
elif scope.type in ('comp_for', 'sync_comp_for'):
|
|
||||||
# Comprehensions currently don't have a special scope in Jedi.
|
|
||||||
return self.create_instance_context(class_context, scope)
|
|
||||||
else:
|
|
||||||
raise NotImplementedError
|
|
||||||
return class_context
|
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "<%s of %s(%s)>" % (self.__class__.__name__, self.class_value,
|
return "<%s of %s(%s)>" % (self.__class__.__name__, self.class_value,
|
||||||
self.arguments)
|
self.arguments)
|
||||||
|
|
||||||
|
|
||||||
class AnonymousInstance(TreeInstance):
|
class AnonymousInstance(_BaseTreeInstance):
|
||||||
def __init__(self, inference_state, parent_context, class_value):
|
pass
|
||||||
super(AnonymousInstance, self).__init__(
|
|
||||||
inference_state,
|
|
||||||
parent_context,
|
|
||||||
class_value,
|
|
||||||
arguments=AnonymousInstanceArguments(self),
|
|
||||||
)
|
|
||||||
|
|
||||||
def get_annotated_class_object(self):
|
|
||||||
return self.class_value # This is the default.
|
|
||||||
|
|
||||||
|
|
||||||
class CompiledInstanceName(compiled.CompiledName):
|
class CompiledInstanceName(compiled.CompiledName):
|
||||||
|
|
||||||
def __init__(self, inference_state, instance, klass, name):
|
def __init__(self, inference_state, instance, klass, name):
|
||||||
super(CompiledInstanceName, self).__init__(
|
super(CompiledInstanceName, self).__init__(
|
||||||
inference_state,
|
inference_state,
|
||||||
@@ -472,9 +467,7 @@ class BoundMethod(FunctionMixin, ValueWrapper):
|
|||||||
return c
|
return c
|
||||||
|
|
||||||
def _get_arguments(self, arguments):
|
def _get_arguments(self, arguments):
|
||||||
if arguments is None:
|
assert arguments is not None
|
||||||
arguments = AnonymousInstanceArguments(self.instance)
|
|
||||||
|
|
||||||
return InstanceArguments(self.instance, arguments)
|
return InstanceArguments(self.instance, arguments)
|
||||||
|
|
||||||
def _as_context(self, arguments=None):
|
def _as_context(self, arguments=None):
|
||||||
|
|||||||
Reference in New Issue
Block a user