diff --git a/jedi/api/__init__.py b/jedi/api/__init__.py index 8550b4bc..251fb078 100644 --- a/jedi/api/__init__.py +++ b/jedi/api/__init__.py @@ -557,14 +557,33 @@ class Script(object): if call is None: return [] + stmt_el = call + while isinstance(stmt_el.parent, pr.StatementElement): + # Go to parent literal/variable until not possible anymore. This + # makes it possible to return the whole expression. + stmt_el = stmt_el.parent + # We can reset the execution since it's a new object + # (fast_parent_copy). + execution_arr, call.execution = call.execution, None + with common.scale_speed_settings(settings.scale_call_signatures): - _callable = lambda: self._evaluator.eval_call(call) + _callable = lambda: self._evaluator.eval_call(stmt_el) origins = cache.cache_call_signatures(_callable, self.source, self._pos, user_stmt) - origins = self._evaluator.eval_call(call) + origins = self._evaluator.eval_call(stmt_el) debug.speed('func_call followed') - return [classes.CallSignature(self._evaluator, o, call, index) + key_name = None + try: + detail = execution_arr[index].assignment_details[0] + except IndexError: + pass + else: + try: + key_name = unicode(detail[0][0].name) + except (IndexError, AttributeError): + pass + return [classes.CallSignature(self._evaluator, o, call, index, key_name) for o in origins if o.is_callable()] diff --git a/jedi/api/classes.py b/jedi/api/classes.py index 3a61711c..ade9f6d8 100644 --- a/jedi/api/classes.py +++ b/jedi/api/classes.py @@ -682,12 +682,28 @@ 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, call, index): + def __init__(self, evaluator, executable, call, index, key_name): super(CallSignature, self).__init__(evaluator, executable) - self.index = index - """ The param index of the current call. """ + self._index = index + self._key_name = key_name self._call = call + @property + def index(self): + """ + The Param index of the current call. + Returns None if the index doesn't is not defined. + """ + if self._key_name is not None: + for i, param in enumerate(self.params): + if self._key_name == param.name: + return i + return None + + if self._index >= len(self.params): + return None + return self._index + @property def bracket_start(self): """ diff --git a/jedi/evaluate/helpers.py b/jedi/evaluate/helpers.py index dae51b48..8930f763 100644 --- a/jedi/evaluate/helpers.py +++ b/jedi/evaluate/helpers.py @@ -123,13 +123,6 @@ def search_call_signatures(user_stmt, position): arr, index = call_signature_array_for_pos(user_stmt, position) if arr is not None: call = arr.parent - while isinstance(call.parent, pr.StatementElement): - # Go to parent literal/variable until not possible anymore. This - # makes it possible to return the whole expression. - call = call.parent - arr.parent.execution = None - if not isinstance(call, pr.Call): - call = None debug.speed('func_call parsed') return call, index diff --git a/test/test_api/test_call_signatures.py b/test/test_api/test_call_signatures.py index 356f8d63..91584982 100644 --- a/test/test_api/test_call_signatures.py +++ b/test/test_api/test_call_signatures.py @@ -26,12 +26,12 @@ class TestCallSignatures(TestCase): run = self._run_simple # simple - s1 = "abs(a, str(" - run(s1, 'abs', 0, 4) - run(s1, 'abs', 1, 6) - run(s1, 'abs', 1, 7) - run(s1, 'abs', 1, 8) - run(s1, 'str', 0, 11) + s1 = "sorted(a, str(" + run(s1, 'sorted', 0, 7) + run(s1, 'sorted', 1, 9) + run(s1, 'sorted', 1, 10) + run(s1, 'sorted', 1, 11) + run(s1, 'str', 0, 14) s2 = "abs(), " run(s2, 'abs', 0, 4) @@ -50,9 +50,9 @@ class TestCallSignatures(TestCase): run(s4, 'abs', 0, 9) #run(s4, 'abs', 1, 10) - s5 = "abs(1,\nif 2:\n def a():" - run(s5, 'abs', 0, 4) - run(s5, 'abs', 1, 6) + s5 = "sorted(1,\nif 2:\n def a():" + run(s5, 'sorted', 0, 7) + run(s5, 'sorted', 1, 9) s6 = "str().center(" run(s6, 'center', 0) @@ -236,3 +236,10 @@ def test_completion_interference(): assert Script('from datetime import ').completions() assert Script('open(').call_signatures() + + +def test_signature_index(): + def get(source): + return Script(source).call_signatures()[0] + + assert get('sorted([], key=a').index == 2