Also return the issues when retruning the executed params

This commit is contained in:
Dave Halter
2018-09-21 00:20:24 +02:00
parent 5fda4a2f8b
commit 43ffcb0802
8 changed files with 74 additions and 47 deletions

View File

@@ -86,9 +86,10 @@ def add(node_context, error_name, node, message=None, typ=Error, payload=None):
# TODO this path is probably not right
module_context = node_context.get_root_context()
module_path = module_context.py__file__()
instance = typ(error_name, module_path, node.start_pos, message)
debug.warning(str(instance), format=False)
node_context.evaluator.analysis.append(instance)
issue_instance = typ(error_name, module_path, node.start_pos, message)
debug.warning(str(issue_instance), format=False)
node_context.evaluator.analysis.append(issue_instance)
return issue_instance
def _check_for_setattr(instance):

View File

@@ -11,7 +11,7 @@ from jedi.evaluate.lazy_context import LazyKnownContext, LazyKnownContexts, \
from jedi.evaluate.filters import ParamName
from jedi.evaluate.base_context import NO_CONTEXTS, ContextSet
from jedi.evaluate.context import iterable
from jedi.evaluate.param import get_executed_params, ExecutedParam
from jedi.evaluate.param import get_executed_params_and_issues, ExecutedParam
def try_iter_content(types, depth=0):
@@ -148,12 +148,12 @@ class AbstractArguments(object):
def unpack(self, funcdef=None):
raise NotImplementedError
def get_executed_params(self, execution_context):
return get_executed_params(execution_context, self)
def get_executed_params_and_issues(self, execution_context):
return get_executed_params_and_issues(execution_context, self)
class AnonymousArguments(AbstractArguments):
def get_executed_params(self, execution_context):
def get_executed_params_and_issues(self, execution_context):
from jedi.evaluate.dynamic import search_params
return search_params(
execution_context.evaluator,

View File

@@ -106,7 +106,7 @@ class FunctionContext(use_metaclass(CachedMetaClass, AbstractFunction)):
if overloaded_funcs:
return OverloadedFunctionContext(
function,
ContextSet.from_iterable(create(f) for f in overloaded_funcs)
[create(f) for f in overloaded_funcs]
)
return function
@@ -273,12 +273,16 @@ class FunctionExecutionContext(TreeContext):
origin_scope=origin_scope)
@evaluator_method_cache()
def get_executed_params(self):
return self.var_args.get_executed_params(self)
def get_executed_params_and_issues(self):
return self.var_args.get_executed_params_and_issues(self)
def matches_signature(self):
executed_params, issues = self.get_executed_params_and_issues()
if issues:
return False
matches = all(executed_param.matches_signature()
for executed_param in self.get_executed_params())
for executed_param in executed_params)
if debug.enable_notice:
signature = parser_utils.get_call_signature(self.tree_node)
if matches:

View File

@@ -32,11 +32,11 @@ class AnonymousInstanceArguments(AnonymousArguments):
def __init__(self, instance):
self._instance = instance
def get_executed_params(self, execution_context):
def get_executed_params_and_issues(self, execution_context):
from jedi.evaluate.dynamic import search_params
tree_params = execution_context.tree_node.get_params()
if not tree_params:
return []
return [], []
self_param = InstanceExecutedParam(self._instance, tree_params[0])
if len(tree_params) == 1:
@@ -49,7 +49,7 @@ class AnonymousInstanceArguments(AnonymousArguments):
execution_context.tree_node
))
executed_params[0] = self_param
return executed_params
return [], executed_params
class AbstractInstanceContext(Context):
@@ -273,7 +273,6 @@ class TreeInstance(AbstractInstanceContext):
if not execution.matches_signature():
# First check if the signature even matches, if not we don't
# need to infer anything.
print('no m', bound)
continue
print(bound)
context_set = define_type_vars_for_execution(
@@ -541,11 +540,11 @@ class InstanceArguments(AbstractArguments):
def get_calling_nodes(self):
return self._arguments.get_calling_nodes()
def get_executed_params(self, execution_context):
def get_executed_params_and_issues(self, execution_context):
if isinstance(self._arguments, AnonymousInstanceArguments):
return self._arguments.get_executed_params(execution_context)
return self._arguments.get_executed_params_and_issues(execution_context)
return super(InstanceArguments, self).get_executed_params(execution_context)
return super(InstanceArguments, self).get_executed_params_and_issues(execution_context)
def __repr__(self):
return '<%s: %s>' % (self.__class__.__name__, self._arguments)

View File

@@ -99,7 +99,7 @@ def search_params(evaluator, execution_context, funcdef):
)
if function_executions:
zipped_params = zip(*list(
function_execution.get_executed_params()
function_execution.get_executed_params_and_issues()[0]
for function_execution in function_executions
))
params = [DynamicExecutedParams(evaluator, executed_params) for executed_params in zipped_params]
@@ -208,7 +208,7 @@ def _check_name_for_execution(evaluator, context, compare_node, name, trailer):
# Here we're trying to find decorators by checking the first
# parameter. It's not very generic though. Should find a better
# solution that also applies to nested decorators.
params = value.parent_context.get_executed_params()
params, _ = value.parent_context.get_executed_params_and_issues()
if len(params) != 1:
continue
values = params[0].infer()

View File

@@ -136,7 +136,7 @@ class ParamName(AbstractTreeName):
return self.get_param().infer()
def get_param(self):
params = self.parent_context.get_executed_params()
params, _ = self.parent_context.get_executed_params_and_issues()
param_node = search_ancestor(self.tree_name, 'param')
return params[param_node.position_index]

View File

@@ -13,7 +13,7 @@ def _add_argument_issue(parent_context, error_name, lazy_context, message):
node = lazy_context.data
if node.parent.type == 'argument':
node = node.parent
analysis.add(parent_context, error_name, node, message)
return analysis.add(parent_context, error_name, node, message)
class ExecutedParam(object):
@@ -58,7 +58,25 @@ class ExecutedParam(object):
return '<%s: %s>' % (self.__class__.__name__, self.string_name)
def get_executed_params(execution_context, var_args):
def get_executed_params_and_issues(execution_context, var_args):
def too_many_args(argument):
m = _error_argument_count(funcdef, len(unpacked_va))
# Just report an error for the first param that is not needed (like
# cPython).
if var_args.get_calling_nodes():
# There might not be a valid calling node so check for that first.
issues.append(
_add_argument_issue(
default_param_context,
'type-error-too-many-arguments',
lazy_context,
message=m
)
)
else:
issues.append(None)
issues = [] # List[Optional[analysis issue]]
result_params = []
param_dict = {}
funcdef = execution_context.tree_node
@@ -94,8 +112,10 @@ def get_executed_params(execution_context, var_args):
m = ("TypeError: %s() got multiple values for keyword argument '%s'."
% (funcdef.name, key))
for node in var_args.get_calling_nodes():
analysis.add(default_param_context, 'type-error-multiple-values',
node, message=m)
issues.append(
analysis.add(default_param_context, 'type-error-multiple-values',
node, message=m)
)
else:
keys_used[key] = ExecutedParam(execution_context, key_param, argument)
key, argument = next(var_arg_iterator, (None, None))
@@ -120,6 +140,8 @@ def get_executed_params(execution_context, var_args):
seq = iterable.FakeSequence(execution_context.evaluator, u'tuple', lazy_context_list)
result_arg = LazyKnownContext(seq)
elif param.star_count == 2:
if argument is not None:
too_many_args(argument)
# **kwargs param
dct = iterable.FakeDict(execution_context.evaluator, dict(non_matching_keys))
result_arg = LazyKnownContext(dct)
@@ -133,8 +155,14 @@ def get_executed_params(execution_context, var_args):
if not keys_only:
for node in var_args.get_calling_nodes():
m = _error_argument_count(funcdef, len(unpacked_va))
analysis.add(default_param_context, 'type-error-too-few-arguments',
node, message=m)
issues.append(
analysis.add(
default_param_context,
'type-error-too-few-arguments',
node,
message=m,
)
)
else:
result_arg = LazyTreeContext(default_param_context, param.default)
else:
@@ -156,34 +184,28 @@ def get_executed_params(execution_context, var_args):
# add a warning only if there's not another one.
for node in var_args.get_calling_nodes():
m = _error_argument_count(funcdef, len(unpacked_va))
analysis.add(default_param_context, 'type-error-too-few-arguments',
node, message=m)
issues.append(
analysis.add(default_param_context, 'type-error-too-few-arguments',
node, message=m)
)
for key, lazy_context in non_matching_keys.items():
m = "TypeError: %s() got an unexpected keyword argument '%s'." \
% (funcdef.name, key)
_add_argument_issue(
default_param_context,
'type-error-keyword-argument',
lazy_context,
message=m
issues.append(
_add_argument_issue(
default_param_context,
'type-error-keyword-argument',
lazy_context,
message=m
)
)
remaining_arguments = list(var_arg_iterator)
if remaining_arguments:
m = _error_argument_count(funcdef, len(unpacked_va))
# Just report an error for the first param that is not needed (like
# cPython).
first_key, lazy_context = remaining_arguments[0]
if var_args.get_calling_nodes():
# There might not be a valid calling node so check for that first.
_add_argument_issue(
default_param_context,
'type-error-too-many-arguments',
lazy_context,
message=m
)
return result_params
too_many_args(lazy_context)
return result_params, issues
def _error_argument_count(funcdef, actual_count):

View File

@@ -250,7 +250,8 @@ def _infer_type_vars_for_execution(execution_context, annotation_dict):
context = execution_context.function_context.get_default_param_context()
annotation_variable_results = {}
for executed_param in execution_context.get_executed_params():
executed_params, _ = execution_context.get_executed_params_and_issues()
for executed_param in executed_params:
try:
annotation_node = annotation_dict[executed_param.string_name]
except KeyError: