Fix all call signature tests.

This commit is contained in:
Dave Halter
2016-06-17 17:03:34 +02:00
parent 32346c6da8
commit 7ddc9c9c78
4 changed files with 44 additions and 22 deletions

View File

@@ -291,14 +291,14 @@ class Script(object):
# self.source, self._pos)
definitions = helpers.evaluate_goto_definition(
self._evaluator,
call_signature_details.leaf
call_signature_details.bracket_leaf.get_previous_leaf()
)
debug.speed('func_call followed')
return [classes.CallSignature(self._evaluator, d.name,
call_signature_details.leaf.start_pos,
call_signature_details.bracket_leaf.start_pos,
call_signature_details.call_index,
call_signature_details.keyword_name)
call_signature_details.keyword_name_str)
for d in definitions if hasattr(d, 'py__call__')]
def _analysis(self):

View File

@@ -629,10 +629,10 @@ class CallSignature(Definition):
It knows what functions you are currently in. e.g. `isinstance(` would
return the `isinstance` function. without `(` it would return nothing.
"""
def __init__(self, evaluator, executable_name, bracket_start_pos, index, key_name):
def __init__(self, evaluator, executable_name, bracket_start_pos, index, key_name_str):
super(CallSignature, self).__init__(evaluator, executable_name)
self._index = index
self._key_name = key_name
self._key_name_str = key_name_str
self._bracket_start_pos = bracket_start_pos
@property
@@ -641,9 +641,9 @@ class CallSignature(Definition):
The Param index of the current call.
Returns None if the index cannot be found in the curent call.
"""
if self._key_name is not None:
if self._key_name_str is not None:
for i, param in enumerate(self.params):
if self._key_name == param.name:
if self._key_name_str == param.name:
return i
if self.params and self.params[-1]._name.get_definition().stars == 2:
return i

View File

@@ -192,7 +192,7 @@ def evaluate_goto_definition(evaluator, leaf):
CallSignatureDetails = namedtuple(
'CallSignatureDetails',
['leaf', 'call_index', 'keyword_name']
['bracket_leaf', 'call_index', 'keyword_name_str']
)
@@ -202,8 +202,25 @@ def _get_call_signature_details_from_error_node(node, position):
if element == '(' and element.end_pos <= position and index > 0:
name = element.get_previous_leaf()
if name.type == 'name':
nodes_before = [c for c in node.children[index:] if c.start_pos < position]
return CallSignatureDetails(name, nodes_before.count(','), None)
if node.children[-1].type == 'arglist':
node = node.children[-1]
children = node.children
else:
# It's an error node, we don't want to match too much, just
# until the parentheses is enough.
children = node.children[index:]
nodes_before = [c for c in children if c.start_pos < position]
key_str = None
if nodes_before:
if nodes_before[-1].type == 'argument':
key_str = nodes_before[-1].children[0].value
elif nodes_before[-1] == '=':
key_str = nodes_before[-2].value
return CallSignatureDetails(
element,
nodes_before.count(','),
key_str
)
def get_call_signature_details(module, position):
@@ -214,8 +231,12 @@ def get_call_signature_details(module, position):
# Now that we know where we are in the syntax tree, we start to look at
# parents for possible function definitions.
node = leaf.parent
name = None
while node is not None:
if node.type in ('funcdef', 'classdef'):
# Don't show call signatures if there's stuff before it that just
# makes it feel strange to have a call signature.
return None
for n in node.children:
if n.start_pos < position and n.type == 'error_node':
result = _get_call_signature_details_from_error_node(n, position)
@@ -223,9 +244,9 @@ def get_call_signature_details(module, position):
return result
if node.type == 'trailer' and node.children[0] == '(':
name = node.get_previous_sibling()
leaf = node.get_previous_leaf()
nodes_before = [c for c in node.children if c.start_pos < position]
return CallSignatureDetails(name, nodes_before.count(','), None)
return CallSignatureDetails(node.children[0], nodes_before.count(','), None)
node = node.parent

View File

@@ -15,7 +15,7 @@ class TestCallSignatures(TestCase):
if not signatures:
assert expected_name is None, \
'There are no signatures, but %s expected.' % expected_name
'There are no signatures, but `%s` expected.' % expected_name
else:
assert signatures[0].name == expected_name
assert signatures[0].index == expected_index
@@ -73,10 +73,11 @@ class TestCallSignatures(TestCase):
run("import time; abc = time; abc.sleep(", 'sleep', 0)
def test_issue_57(self):
# jedi #57
s = "def func(alpha, beta): pass\n" \
"func(alpha='101',"
run(s, 'func', 0, column=13, line=2)
self._run_simple(s, 'func', 0, column=13, line=2)
def test_flows(self):
# jedi-vim #9
@@ -178,9 +179,7 @@ class TestCallSignatures(TestCase):
def test_whitespace_before_bracket(self):
self._run('str (', 'str', 0)
self._run('str (";', 'str', 0)
# TODO this is not actually valid Python, the newline token should be
# ignored.
self._run('str\n(', 'str', 0)
self._run('str\n(', None)
def test_brackets_in_string_literals(self):
self._run('str (" (', 'str', 0)
@@ -191,7 +190,8 @@ class TestCallSignatures(TestCase):
Function definitions (and other tokens that cannot exist within call
signatures) should break and not be able to return a call signature.
"""
assert not Script('str(\ndef x').call_signatures()
assert not self._run('str(\ndef x', 'str', 0)
assert not Script('str(\ndef x(): pass').call_signatures()
def test_flow_call(self):
assert not Script('if (1').call_signatures()
@@ -316,11 +316,12 @@ def test_completion_interference():
assert Script('open(').call_signatures()
def test_signature_index():
def get(source):
return Script(source).call_signatures()[0]
def test_keyword_argument_index():
def get(source, column=None):
return Script(source, column=column).call_signatures()[0]
assert get('sorted([], key=a').index == 2
assert get('sorted([], key=').index == 2
assert get('sorted([], no_key=a').index is None
args_func = 'def foo(*kwargs): pass\n'