1
0
forked from VimPlug/jedi

moved the param generation into another file

This commit is contained in:
Dave Halter
2014-01-07 14:33:27 +01:00
parent 69afc2482a
commit 1881a24e73
2 changed files with 202 additions and 188 deletions

View File

@@ -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)