1
0
forked from VimPlug/jedi

Refactor AnonymousInstance/TreeInstance, so that the anonymous instance doesn't have to use arguments

This commit is contained in:
Dave Halter
2019-09-03 21:56:48 +02:00
parent acda3527cb
commit 3a74d65404

View File

@@ -103,12 +103,11 @@ class MethodExecutionContext(FunctionExecutionContext):
class AbstractInstanceValue(Value):
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)
# Generated instances are classes that are just generated by self
# (No arguments) used.
self.class_value = class_value
self.arguments = arguments
def is_instance(self):
return True
@@ -135,14 +134,14 @@ class AbstractInstanceValue(Value):
return [s.bind(self) for s in call_funcs.get_signatures()]
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):
def __init__(self, inference_state, parent_context, class_value, arguments):
self._original_arguments = arguments
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):
class_value = self.get_annotated_class_object()
@@ -158,7 +157,7 @@ class CompiledInstance(AbstractInstanceValue):
return compiled.CompiledValueName(self, self.class_value.name.string_name)
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:
return NO_VALUES
@@ -168,20 +167,7 @@ class CompiledInstance(AbstractInstanceValue):
return False
class TreeInstance(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
class _BaseTreeInstance(AbstractInstanceValue):
@property
def array_type(self):
name = self.class_value.py__name__()
@@ -194,35 +180,6 @@ class TreeInstance(AbstractInstanceValue):
def name(self):
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):
class_value = self.get_annotated_class_object()
if include_self_names:
@@ -254,6 +211,38 @@ class TreeInstance(AbstractInstanceValue):
for signature in init.get_signatures():
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):
'''
Since nothing was inferred, now check the __getattr__ and
@@ -276,29 +265,6 @@ class TreeInstance(AbstractInstanceValue):
self.get_function_slot_names(u'__getattribute__'))
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):
names = self.get_function_slot_names(u'__getitem__')
if not names:
@@ -373,55 +339,84 @@ class TreeInstance(AbstractInstanceValue):
for name in names
)
@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,
class TreeInstance(_BaseTreeInstance):
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(_BaseTreeInstance, self).__init__(inference_state, parent_context,
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)
if scope.name.value == '__init__' and parent_context == class_context:
return bound_method.as_context(self.arguments)
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 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:
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
if key == index:
return lazy_context.infer()
return super(TreeInstance, self).py__simple_getitem__(index)
def __repr__(self):
return "<%s of %s(%s)>" % (self.__class__.__name__, self.class_value,
self.arguments)
class AnonymousInstance(TreeInstance):
def __init__(self, inference_state, parent_context, class_value):
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 AnonymousInstance(_BaseTreeInstance):
pass
class CompiledInstanceName(compiled.CompiledName):
def __init__(self, inference_state, instance, klass, name):
super(CompiledInstanceName, self).__init__(
inference_state,
@@ -472,9 +467,7 @@ class BoundMethod(FunctionMixin, ValueWrapper):
return c
def _get_arguments(self, arguments):
if arguments is None:
arguments = AnonymousInstanceArguments(self.instance)
assert arguments is not None
return InstanceArguments(self.instance, arguments)
def _as_context(self, arguments=None):