Fix class tests

This commit is contained in:
Dave Halter
2019-08-17 23:52:52 +02:00
parent 895e774962
commit 0c419a5094
11 changed files with 55 additions and 38 deletions

View File

@@ -284,7 +284,7 @@ class Completion:
cls = tree.search_ancestor(leaf, 'classdef') cls = tree.search_ancestor(leaf, 'classdef')
if isinstance(cls, (tree.Class, tree.Function)): if isinstance(cls, (tree.Class, tree.Function)):
# Complete the methods that are defined in the super classes. # Complete the methods that are defined in the super classes.
random_value = self._module_context.create_context( random_context = self._module_context.create_context(
cls, cls,
node_is_value=True node_is_value=True
) )
@@ -294,7 +294,8 @@ class Completion:
if cls.start_pos[1] >= leaf.start_pos[1]: if cls.start_pos[1] >= leaf.start_pos[1]:
return return
filters = random_value.get_filters(is_instance=True) # TODO _value private access!
filters = random_context._value.get_filters(is_instance=True)
# The first dict is the dictionary of class itself. # The first dict is the dictionary of class itself.
next(filters) next(filters)
for filter in filters: for filter in filters:

View File

@@ -349,13 +349,13 @@ class InferenceState(object):
new_dotted.children[index - 1:] = [] new_dotted.children[index - 1:] = []
values = context.infer_node(new_dotted) values = context.infer_node(new_dotted)
return unite( return unite(
value.py__getattribute__(name, name_value=value, is_goto=True) value.goto(name, name_value=value)
for value in values for value in values
) )
if node_type == 'trailer' and par.children[0] == '.': if node_type == 'trailer' and par.children[0] == '.':
values = helpers.infer_call_of_leaf(context, name, cut_own_trailer=True) values = helpers.infer_call_of_leaf(context, name, cut_own_trailer=True)
return values.py__getattribute__(name, name_context=context, is_goto=True) return values.goto(name, name_context=context)
else: else:
stmt = tree.search_ancestor( stmt = tree.search_ancestor(
name, 'expr_stmt', 'lambdef' name, 'expr_stmt', 'lambdef'
@@ -391,8 +391,9 @@ class InferenceState(object):
if is_funcdef: if is_funcdef:
func = FunctionValue.from_context(parent_context, scope_node) func = FunctionValue.from_context(parent_context, scope_node)
if parent_context.is_class(): if parent_context.is_class():
# TODO _value private access!
instance = AnonymousInstance( instance = AnonymousInstance(
self, parent_context.parent_context, parent_context) self, parent_context.parent_context, parent_context._value)
func = BoundMethod( func = BoundMethod(
instance=instance, instance=instance,
function=func function=func
@@ -402,7 +403,7 @@ class InferenceState(object):
return func.get_function_execution() return func.get_function_execution()
return func return func
elif scope_node.type == 'classdef': elif scope_node.type == 'classdef':
return ClassValue(self, parent_context, scope_node) return ClassValue(self, parent_context, scope_node).as_context()
elif scope_node.type in ('comp_for', 'sync_comp_for'): elif scope_node.type in ('comp_for', 'sync_comp_for'):
if node.start_pos >= scope_node.children[-1].start_pos: if node.start_pos >= scope_node.children[-1].start_pos:
return parent_context return parent_context

View File

@@ -71,6 +71,18 @@ class HelperValueMixin(object):
filters = f.get_value_filters() filters = f.get_value_filters()
return f.find(filters, attribute_lookup=True) return f.find(filters, attribute_lookup=True)
def goto(self, name_or_str, name_context=None, analysis_errors=True):
"""
:param position: Position of the last statement -> tuple of line, column
"""
if name_context is None:
name_context = self
from jedi.inference import finder
f = finder.NameFinder(self.inference_state, self, name_context, name_or_str,
analysis_errors=analysis_errors)
filters = f.get_value_filters()
return f.filter_name(filters)
def py__await__(self): def py__await__(self):
await_value_set = self.py__getattribute__(u"__await__") await_value_set = self.py__getattribute__(u"__await__")
if not await_value_set: if not await_value_set:
@@ -403,9 +415,10 @@ class ValueSet(BaseValueSet):
def execute_with_values(self, *args, **kwargs): def execute_with_values(self, *args, **kwargs):
return ValueSet.from_sets(c.execute_with_values(*args, **kwargs) for c in self._set) return ValueSet.from_sets(c.execute_with_values(*args, **kwargs) for c in self._set)
def goto(self, *args, **kwargs):
return reduce(add, [c.goto(*args, **kwargs) for c in self._set], [])
def py__getattribute__(self, *args, **kwargs): def py__getattribute__(self, *args, **kwargs):
if kwargs.get('is_goto'):
return reduce(add, [c.py__getattribute__(*args, **kwargs) for c in self._set], [])
return ValueSet.from_sets(c.py__getattribute__(*args, **kwargs) for c in self._set) return ValueSet.from_sets(c.py__getattribute__(*args, **kwargs) for c in self._set)
def get_item(self, *args, **kwargs): def get_item(self, *args, **kwargs):
@@ -422,9 +435,6 @@ class ValueSet(BaseValueSet):
value_set |= method() value_set |= method()
return value_set return value_set
def as_context(self):
return [v.as_context() for v in self._set]
def gather_annotation_classes(self): def gather_annotation_classes(self):
return ValueSet.from_sets([c.gather_annotation_classes() for c in self._set]) return ValueSet.from_sets([c.gather_annotation_classes() for c in self._set])

View File

@@ -72,6 +72,9 @@ class AbstractContext(object):
def py__name__(self): def py__name__(self):
return self._value.py__name__() return self._value.py__name__()
def get_qualified_names(self):
return self._value.get_qualified_names()
def py__doc__(self): def py__doc__(self):
return self._value.py__doc__() return self._value.py__doc__()
@@ -103,6 +106,7 @@ class ModuleContext(AbstractContext):
def get_filters(self, until_position=None, origin_scope=None): def get_filters(self, until_position=None, origin_scope=None):
filters = self._value.get_filters(origin_scope) filters = self._value.get_filters(origin_scope)
# Skip the first filter and replace it. # Skip the first filter and replace it.
next(filters)
yield MergedFilter( yield MergedFilter(
ParserTreeFilter( ParserTreeFilter(
context=self, context=self,

View File

@@ -169,11 +169,11 @@ def _infer_param(execution_context, param):
param_comment = params_comments[index] param_comment = params_comments[index]
return _infer_annotation_string( return _infer_annotation_string(
execution_context.function_value.get_default_param_value(), execution_context.function_value.get_default_param_context(),
param_comment param_comment
) )
# Annotations are like default params and resolve in the same way. # Annotations are like default params and resolve in the same way.
value = execution_context.function_value.get_default_param_value() value = execution_context.function_value.get_default_param_context()
return infer_annotation(value, annotation) return infer_annotation(value, annotation)
@@ -210,13 +210,13 @@ def infer_return_types(function_execution_context):
return NO_VALUES return NO_VALUES
return _infer_annotation_string( return _infer_annotation_string(
function_execution_context.function_value.get_default_param_value(), function_execution_context.function_value.get_default_param_context(),
match.group(1).strip() match.group(1).strip()
).execute_annotation() ).execute_annotation()
if annotation is None: if annotation is None:
return NO_VALUES return NO_VALUES
value = function_execution_context.function_value.get_default_param_value() value = function_execution_context.function_value.get_default_param_context()
unknown_type_vars = list(find_unknown_type_vars(value, annotation)) unknown_type_vars = list(find_unknown_type_vars(value, annotation))
annotation_values = infer_annotation(value, annotation) annotation_values = infer_annotation(value, annotation)
if not unknown_type_vars: if not unknown_type_vars:
@@ -241,7 +241,7 @@ def infer_type_vars_for_execution(execution_context, annotation_dict):
2. Infer type vars with the execution state we have. 2. Infer type vars with the execution state we have.
3. Return the union of all type vars that have been found. 3. Return the union of all type vars that have been found.
""" """
value = execution_context.function_value.get_default_param_value() value = execution_context.function_value.get_default_param_context()
annotation_variable_results = {} annotation_variable_results = {}
executed_params, _ = execution_context.get_executed_params_and_issues() executed_params, _ = execution_context.get_executed_params_and_issues()

View File

@@ -69,7 +69,7 @@ def _try_stub_to_python_names(names, prefer_stub_to_compiled=False):
ignore_compiled=prefer_stub_to_compiled, ignore_compiled=prefer_stub_to_compiled,
) )
if values and name_list: if values and name_list:
new_names = values.py__getattribute__(name_list[-1], is_goto=True) new_names = values.goto(name_list[-1])
for new_name in new_names: for new_name in new_names:
yield new_name yield new_name
if new_names: if new_names:
@@ -121,7 +121,7 @@ def _python_to_stub_names(names, fallback_to_python=False):
for name in name_list[:-1]: for name in name_list[:-1]:
stubs = stubs.py__getattribute__(name) stubs = stubs.py__getattribute__(name)
if stubs and name_list: if stubs and name_list:
new_names = stubs.py__getattribute__(name_list[-1], is_goto=True) new_names = stubs.goto(name_list[-1])
for new_name in new_names: for new_name in new_names:
yield new_name yield new_name
if new_names: if new_names:

View File

@@ -89,7 +89,7 @@ def get_executed_params_and_issues(execution_context, arguments):
# Default params are part of the value where the function was defined. # Default params are part of the value where the function was defined.
# This means that they might have access on class variables that the # This means that they might have access on class variables that the
# function itself doesn't have. # function itself doesn't have.
default_param_value = execution_context.function_value.get_default_param_value() default_param_context = execution_context.function_value.get_default_param_context()
for param in funcdef.get_params(): for param in funcdef.get_params():
param_dict[param.name.value] = param param_dict[param.name.value] = param
@@ -172,7 +172,7 @@ def get_executed_params_and_issues(execution_context, arguments):
) )
) )
else: else:
result_arg = LazyTreeValue(default_param_value, param.default) result_arg = LazyTreeValue(default_param_context, param.default)
is_default = True is_default = True
else: else:
result_arg = argument result_arg = argument

View File

@@ -93,6 +93,9 @@ class FunctionMixin(object):
return FunctionExecutionContext(self, arguments) return FunctionExecutionContext(self, arguments)
def as_context(self):
return self.get_function_execution()
def get_signatures(self): def get_signatures(self):
return [TreeSignature(f) for f in self.get_signature_functions()] return [TreeSignature(f) for f in self.get_signature_functions()]
@@ -137,7 +140,7 @@ class FunctionValue(use_metaclass(CachedMetaClass, FunctionMixin, FunctionAndCla
c, = values_from_qualified_names(self.inference_state, u'types', u'FunctionType') c, = values_from_qualified_names(self.inference_state, u'types', u'FunctionType')
return c return c
def get_default_param_value(self): def get_default_param_context(self):
return self.parent_context return self.parent_context
def get_signature_functions(self): def get_signature_functions(self):
@@ -145,17 +148,17 @@ class FunctionValue(use_metaclass(CachedMetaClass, FunctionMixin, FunctionAndCla
class MethodValue(FunctionValue): class MethodValue(FunctionValue):
def __init__(self, inference_state, class_value, *args, **kwargs): def __init__(self, inference_state, class_context, *args, **kwargs):
super(MethodValue, self).__init__(inference_state, *args, **kwargs) super(MethodValue, self).__init__(inference_state, *args, **kwargs)
self.class_value = class_value self.class_context = class_context
def get_default_param_value(self): def get_default_param_context(self):
return self.class_value return self.class_context
def get_qualified_names(self): def get_qualified_names(self):
# Need to implement this, because the parent value of a method # Need to implement this, because the parent value of a method
# value is not the class value but the module. # value is not the class value but the module.
names = self.class_value.get_qualified_names() names = self.class_context.get_qualified_names()
if names is None: if names is None:
return None return None
return names + (self.py__name__(),) return names + (self.py__name__(),)

View File

@@ -106,7 +106,7 @@ class ClassFilter(ParserTreeFilter):
def _equals_origin_scope(self): def _equals_origin_scope(self):
node = self._origin_scope node = self._origin_scope
while node is not None: while node is not None:
if node == self._parser_scope or node == self.value: if node == self._parser_scope or node == self.context:
return True return True
node = get_cached_parent_scope(self._used_names, node) node = get_cached_parent_scope(self._used_names, node)
return False return False

View File

@@ -158,7 +158,7 @@ def _follow_param(inference_state, arguments, index):
return lazy_value.infer() return lazy_value.infer()
def argument_clinic(string, want_obj=False, want_value=False, def argument_clinic(string, want_obj=False, want_context=False,
want_arguments=False, want_inference_state=False, want_arguments=False, want_inference_state=False,
want_callback=False): want_callback=False):
""" """
@@ -174,8 +174,8 @@ def argument_clinic(string, want_obj=False, want_value=False,
assert not kwargs # Python 2... assert not kwargs # Python 2...
debug.dbg('builtin start %s' % obj, color='MAGENTA') debug.dbg('builtin start %s' % obj, color='MAGENTA')
result = NO_VALUES result = NO_VALUES
if want_value: if want_context:
kwargs['value'] = arguments.value kwargs['context'] = arguments.context
if want_obj: if want_obj:
kwargs['obj'] = obj kwargs['obj'] = obj
if want_inference_state: if want_inference_state:
@@ -268,11 +268,11 @@ class SuperInstance(LazyValueWrapper):
yield f yield f
@argument_clinic('[type[, obj]], /', want_value=True) @argument_clinic('[type[, obj]], /', want_context=True)
def builtins_super(types, objects, value): def builtins_super(types, objects, context):
if isinstance(value, FunctionExecutionContext): if isinstance(context, FunctionExecutionContext):
if isinstance(value.var_args, InstanceArguments): if isinstance(context.var_args, InstanceArguments):
instance = value.var_args.instance instance = context.var_args.instance
# TODO if a class is given it doesn't have to be the direct super # TODO if a class is given it doesn't have to be the direct super
# class, it can be an anecestor from long ago. # class, it can be an anecestor from long ago.
return ValueSet({SuperInstance(instance.inference_state, instance)}) return ValueSet({SuperInstance(instance.inference_state, instance)})

View File

@@ -231,9 +231,7 @@ class IntegrationTestCase(object):
#if user_context._value.api_type == 'function': #if user_context._value.api_type == 'function':
# user_context = user_context.get_function_execution() # user_context = user_context.get_function_execution()
node.parent = user_context.tree_node node.parent = user_context.tree_node
results = convert_values( results = convert_values(user_context.infer_node(node))
user_context.infer_node(node),
)
if not results: if not results:
raise Exception('Could not resolve %s on line %s' raise Exception('Could not resolve %s on line %s'
% (match.string, self.line_nr - 1)) % (match.string, self.line_nr - 1))