forked from VimPlug/jedi
moved the param generation into another file
This commit is contained in:
@@ -11,7 +11,7 @@ they change classes in Python 3.
|
||||
"""
|
||||
import copy
|
||||
|
||||
from jedi._compatibility import use_metaclass, next, unicode
|
||||
from jedi._compatibility import use_metaclass, unicode
|
||||
from jedi.parser import representation as pr
|
||||
from jedi import debug
|
||||
from jedi import common
|
||||
@@ -21,6 +21,7 @@ from jedi.evaluate import recursion
|
||||
from jedi.evaluate import iterable
|
||||
from jedi.evaluate import docstrings
|
||||
from jedi.evaluate import helpers
|
||||
from jedi.evaluate import param
|
||||
|
||||
|
||||
class Executable(pr.IsScope):
|
||||
@@ -421,183 +422,7 @@ class FunctionExecution(Executable):
|
||||
This needs to be here, because Instance can have __init__ functions,
|
||||
which act the same way as normal functions.
|
||||
"""
|
||||
def gen_param_name_copy(param, keys=(), values=(), array_type=None):
|
||||
"""
|
||||
Create a param with the original scope (of varargs) as parent.
|
||||
"""
|
||||
if isinstance(self.var_args, pr.Array):
|
||||
parent = self.var_args.parent
|
||||
start_pos = self.var_args.start_pos
|
||||
else:
|
||||
parent = self.base
|
||||
start_pos = 0, 0
|
||||
|
||||
new_param = copy.copy(param)
|
||||
new_param.is_generated = True
|
||||
if parent is not None:
|
||||
new_param.parent = parent
|
||||
|
||||
# create an Array (-> needed for *args/**kwargs tuples/dicts)
|
||||
arr = pr.Array(self._sub_module, start_pos, array_type, parent)
|
||||
arr.values = values
|
||||
key_stmts = []
|
||||
for key in keys:
|
||||
stmt = pr.Statement(self._sub_module, [], start_pos, None)
|
||||
stmt._expression_list = [key]
|
||||
key_stmts.append(stmt)
|
||||
arr.keys = key_stmts
|
||||
arr.type = array_type
|
||||
|
||||
new_param._expression_list = [arr]
|
||||
|
||||
name = copy.copy(param.get_name())
|
||||
name.parent = new_param
|
||||
return name
|
||||
|
||||
result = []
|
||||
start_offset = 0
|
||||
if isinstance(self.base, InstanceElement):
|
||||
# Care for self -> just exclude it and add the instance
|
||||
start_offset = 1
|
||||
self_name = copy.copy(self.base.params[0].get_name())
|
||||
self_name.parent = self.base.instance
|
||||
result.append(self_name)
|
||||
|
||||
param_dict = {}
|
||||
for param in self.base.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 = self._get_var_args_iterator()
|
||||
|
||||
non_matching_keys = []
|
||||
keys_used = set()
|
||||
keys_only = False
|
||||
for param in self.base.params[start_offset:]:
|
||||
# The value and key can both be null. There, the defaults apply.
|
||||
# args / kwargs will just be empty arrays / dicts, respectively.
|
||||
# Wrong value count is just ignored. If you try to test cases that
|
||||
# are not allowed in Python, Jedi will maybe not show any
|
||||
# completions.
|
||||
key, value = next(var_arg_iterator, (None, None))
|
||||
while key:
|
||||
keys_only = True
|
||||
try:
|
||||
key_param = param_dict[str(key)]
|
||||
except KeyError:
|
||||
non_matching_keys.append((key, value))
|
||||
else:
|
||||
keys_used.add(str(key))
|
||||
result.append(gen_param_name_copy(key_param,
|
||||
values=[value]))
|
||||
key, value = next(var_arg_iterator, (None, None))
|
||||
|
||||
expression_list = param.expression_list()
|
||||
keys = []
|
||||
values = []
|
||||
array_type = None
|
||||
ignore_creation = False
|
||||
if expression_list[0] == '*':
|
||||
# *args param
|
||||
array_type = pr.Array.TUPLE
|
||||
if value:
|
||||
values.append(value)
|
||||
for key, value in var_arg_iterator:
|
||||
# Iterate until a key argument is found.
|
||||
if key:
|
||||
var_arg_iterator.push_back((key, value))
|
||||
break
|
||||
values.append(value)
|
||||
elif expression_list[0] == '**':
|
||||
# **kwargs param
|
||||
array_type = pr.Array.DICT
|
||||
if non_matching_keys:
|
||||
keys, values = zip(*non_matching_keys)
|
||||
elif not keys_only:
|
||||
# normal param
|
||||
if value is not None:
|
||||
values = [value]
|
||||
else:
|
||||
if param.assignment_details:
|
||||
# No value: return the default values.
|
||||
ignore_creation = True
|
||||
result.append(param.get_name())
|
||||
param.is_generated = True
|
||||
else:
|
||||
# If there is no assignment detail, that means there is
|
||||
# no assignment, just the result. Therefore nothing has
|
||||
# to be returned.
|
||||
values = []
|
||||
|
||||
# Just ignore all the params that are without a key, after one
|
||||
# keyword argument was set.
|
||||
if not ignore_creation and (not keys_only or expression_list[0] == '**'):
|
||||
keys_used.add(str(key))
|
||||
result.append(gen_param_name_copy(param, keys=keys,
|
||||
values=values, array_type=array_type))
|
||||
|
||||
if keys_only:
|
||||
# sometimes param arguments are not completely written (which would
|
||||
# create an Exception, but we have to handle that).
|
||||
for k in set(param_dict) - keys_used:
|
||||
result.append(gen_param_name_copy(param_dict[k]))
|
||||
return result
|
||||
|
||||
def _get_var_args_iterator(self):
|
||||
"""
|
||||
Yields a key/value pair, the key is None, if its not a named arg.
|
||||
"""
|
||||
def iterate():
|
||||
# `var_args` is typically an Array, and not a list.
|
||||
for stmt in self.var_args:
|
||||
if not isinstance(stmt, pr.Statement):
|
||||
if stmt is None:
|
||||
yield None, None
|
||||
continue
|
||||
old = stmt
|
||||
# generate a statement if it's not already one.
|
||||
module = builtin.Builtin.scope
|
||||
stmt = pr.Statement(module, [], (0, 0), None)
|
||||
stmt._expression_list = [old]
|
||||
|
||||
# *args
|
||||
expression_list = stmt.expression_list()
|
||||
if not len(expression_list):
|
||||
continue
|
||||
if expression_list[0] == '*':
|
||||
arrays = self._evaluator.eval_expression_list(expression_list[1:])
|
||||
# *args must be some sort of an array, otherwise -> ignore
|
||||
|
||||
for array in arrays:
|
||||
if isinstance(array, iterable.Array):
|
||||
for field_stmt in array: # yield from plz!
|
||||
yield None, field_stmt
|
||||
elif isinstance(array, iterable.Generator):
|
||||
for field_stmt in array.iter_content():
|
||||
yield None, FakeStatement(field_stmt)
|
||||
# **kwargs
|
||||
elif expression_list[0] == '**':
|
||||
arrays = self._evaluator.eval_expression_list(expression_list[1:])
|
||||
for array in arrays:
|
||||
if isinstance(array, iterable.Array):
|
||||
for key_stmt, value_stmt in array.items():
|
||||
# first index, is the key if syntactically correct
|
||||
call = key_stmt.expression_list()[0]
|
||||
if isinstance(call, pr.Name):
|
||||
yield call, value_stmt
|
||||
elif isinstance(call, pr.Call):
|
||||
yield call.name, value_stmt
|
||||
# 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
|
||||
else:
|
||||
yield None, stmt
|
||||
|
||||
return iter(common.PushBackIterator(iterate()))
|
||||
return param.get_params(self._evaluator, self.base, self.var_args)
|
||||
|
||||
def get_defined_names(self):
|
||||
"""
|
||||
@@ -676,13 +501,3 @@ class FunctionExecution(Executable):
|
||||
def __repr__(self):
|
||||
return "<%s of %s>" % \
|
||||
(type(self).__name__, self.base)
|
||||
|
||||
|
||||
class FakeStatement(pr.Statement):
|
||||
class SubModule():
|
||||
line_offset = 0
|
||||
|
||||
def __init__(self, content):
|
||||
cls = type(self)
|
||||
p = 0, 0
|
||||
super(cls, self).__init__(cls.SubModule, [content], p, p)
|
||||
|
||||
Reference in New Issue
Block a user