mirror of
https://github.com/davidhalter/jedi.git
synced 2025-12-06 22:14:27 +08:00
temporary very unfinished solution for the *args/**kwargs combination problem, if they are used in common with dynamic params. This doesn't solve the issue entirely, but it's at least a start and will probably solve all autocompletion issues. However, static analysis needs a little bit more than that.
This commit is contained in:
@@ -54,7 +54,7 @@ class NameFinder(object):
|
||||
% (self._last_filter_name_scope, self.name_str))
|
||||
analysis.add(self._evaluator, err_type, self.name_str, message)
|
||||
|
||||
debug.dbg('finder._names_to_types: %s, old: %s', names, types)
|
||||
debug.dbg('finder._names_to_types: %s -> %s', names, types)
|
||||
return self._resolve_descriptors(types)
|
||||
|
||||
def scopes(self, search_global=False):
|
||||
|
||||
@@ -75,7 +75,8 @@ def get_params(evaluator, func, var_args):
|
||||
for param in func.params:
|
||||
param_dict[str(param.get_name())] = param
|
||||
# There may be calls, which don't fit all the params, this just ignores it.
|
||||
var_arg_iterator = common.PushBackIterator(_var_args_iterator(evaluator, var_args))
|
||||
va = _unpack_var_args(evaluator, var_args, func.params)
|
||||
var_arg_iterator = common.PushBackIterator(iter(va))
|
||||
|
||||
non_matching_keys = []
|
||||
keys_used = set()
|
||||
@@ -125,12 +126,14 @@ def get_params(evaluator, func, var_args):
|
||||
break
|
||||
lst_values.append(va_values)
|
||||
if lst_values[0]:
|
||||
#print('args', lst_values[0][0].parent.start_pos)
|
||||
values = [helpers.stmts_to_stmt(v) for v in lst_values]
|
||||
elif param.stars == 2:
|
||||
# **kwargs param
|
||||
array_type = pr.Array.DICT
|
||||
if non_matching_keys:
|
||||
keys, values = zip(*non_matching_keys)
|
||||
# print('kw', values[0][0].parent.start_pos)
|
||||
values = [helpers.stmts_to_stmt(list(v)) for v in values]
|
||||
non_matching_keys = []
|
||||
else:
|
||||
@@ -168,7 +171,8 @@ def get_params(evaluator, func, var_args):
|
||||
for k in set(param_dict) - keys_used:
|
||||
result.append(_gen_param_name_copy(func, var_args, param_dict[k]))
|
||||
|
||||
if not non_matching_keys and not had_multiple_value_error:
|
||||
if not (non_matching_keys or had_multiple_value_error
|
||||
or param_dict[k].stars):
|
||||
# add a warning only if there's not another one.
|
||||
calling_va = _get_calling_var_args(evaluator, var_args)
|
||||
if calling_va is not None:
|
||||
@@ -191,15 +195,17 @@ def get_params(evaluator, func, var_args):
|
||||
return result
|
||||
|
||||
|
||||
def _var_args_iterator(evaluator, var_args):
|
||||
def _unpack_var_args(evaluator, var_args, params):
|
||||
"""
|
||||
Yields a key/value pair, the key is None, if its not a named arg.
|
||||
"""
|
||||
argument_list = []
|
||||
# `var_args` is typically an Array, and not a list.
|
||||
for stmt in var_args:
|
||||
if not isinstance(stmt, pr.Statement):
|
||||
if stmt is None:
|
||||
yield None, []
|
||||
argument_list.append((None, []))
|
||||
# TODO generate warning?
|
||||
continue
|
||||
old = stmt
|
||||
# generate a statement if it's not already one.
|
||||
@@ -213,7 +219,7 @@ def _var_args_iterator(evaluator, var_args):
|
||||
arrays = evaluator.eval_expression_list(expression_list[1:])
|
||||
iterators = [_iterate_star_args(a) for a in arrays]
|
||||
for values in list(zip_longest(*iterators)):
|
||||
yield None, [v for v in values if v is not None]
|
||||
argument_list.append((None, [v for v in values if v is not None]))
|
||||
# **kwargs
|
||||
elif expression_list[0] == '**':
|
||||
dct = {}
|
||||
@@ -223,17 +229,28 @@ def _var_args_iterator(evaluator, var_args):
|
||||
dct[name][1].add(value)
|
||||
except KeyError:
|
||||
dct[name] = key, set([value])
|
||||
|
||||
for key, values in dct.values():
|
||||
yield key, values
|
||||
for i, p in enumerate(params):
|
||||
if str(p.get_name()) == str(key) and not p.stars:
|
||||
try:
|
||||
if argument_list[i][0] is None:
|
||||
argument_list[i][1].extend(values)
|
||||
break
|
||||
except IndexError:
|
||||
pass
|
||||
else:
|
||||
argument_list.append((key, values))
|
||||
# Normal arguments (including key arguments).
|
||||
else:
|
||||
if stmt.assignment_details:
|
||||
key_arr, op = stmt.assignment_details[0]
|
||||
# named parameter
|
||||
if key_arr and isinstance(key_arr[0], pr.Call):
|
||||
yield key_arr[0].name, [stmt]
|
||||
argument_list.append((key_arr[0].name, [stmt]))
|
||||
else:
|
||||
yield None, [stmt]
|
||||
argument_list.append((None, [stmt]))
|
||||
return argument_list
|
||||
|
||||
|
||||
def _iterate_star_args(array):
|
||||
|
||||
@@ -61,3 +61,35 @@ kwargs_nested()
|
||||
kwargs_nested(c=2, d=4)
|
||||
#! 13 type-error-multiple-values
|
||||
kwargs_nested(c=2, a=4)
|
||||
|
||||
# -----------------
|
||||
# mixed *args/**kwargs
|
||||
# -----------------
|
||||
|
||||
def simple_mixed(a, b, c):
|
||||
return b
|
||||
|
||||
|
||||
def mixed(*args, **kwargs):
|
||||
return simple_mixed(1, *args, **kwargs)
|
||||
|
||||
mixed(1, 2)
|
||||
mixed(1, c=2)
|
||||
mixed(b=2, c=3)
|
||||
mixed(c=4, b='')
|
||||
|
||||
# need separate functions, otherwise these might swallow the errors
|
||||
def mixed2(*args, **kwargs):
|
||||
return simple_mixed(1, *args, **kwargs)
|
||||
|
||||
|
||||
#! 6 type-error-too-few-arguments
|
||||
mixed2(c=2)
|
||||
#! 6 type-error-too-few-arguments
|
||||
mixed2(3)
|
||||
#! 13 type-error-too-many-arguments
|
||||
mixed2(3, 4, 5)
|
||||
#! 13 type-error-too-many-arguments
|
||||
mixed2(3, 4, c=5)
|
||||
#! 6 type-error-multiple-values
|
||||
mixed2(3, b=5)
|
||||
|
||||
@@ -26,12 +26,12 @@ def assert_static_analysis(case, actual, desired):
|
||||
d = set(desired)
|
||||
assert actual == desired, """
|
||||
Test %r failed.
|
||||
specified, not raised = %s
|
||||
missing = %s
|
||||
not raised = %s
|
||||
unspecified = %s
|
||||
""" % (case, sorted(d - a), sorted(a - d))
|
||||
|
||||
|
||||
def test_integration(case, monkeypatch):
|
||||
def test_completion(case, monkeypatch):
|
||||
if case.skip is not None:
|
||||
pytest.skip(case.skip)
|
||||
repo_root = helpers.root_dir
|
||||
|
||||
Reference in New Issue
Block a user