From 54bd0b437faa5a9c1d0b122d883e7b830a557024 Mon Sep 17 00:00:00 2001 From: Dave Halter Date: Wed, 1 Jan 2020 18:55:38 +0100 Subject: [PATCH] Make sure that equals will only be added to keyword arguments and not just randomly --- jedi/api/classes.py | 6 +----- jedi/api/completion.py | 8 +++++++- test/completion/named_param.py | 20 ++++++++++---------- test/test_api/test_completion.py | 12 ++++++++++++ test/test_api/test_interpreter.py | 8 ++++---- 5 files changed, 34 insertions(+), 20 deletions(-) diff --git a/jedi/api/classes.py b/jedi/api/classes.py index ec4329fd..5c6fb0e5 100644 --- a/jedi/api/classes.py +++ b/jedi/api/classes.py @@ -456,11 +456,7 @@ class Completion(BaseDefinition): and self.type == 'function': append = '(' - if self._name.api_type == 'param' and self._stack is not None: - nonterminals = [stack_node.nonterminal for stack_node in self._stack] - if 'trailer' in nonterminals and 'argument' not in nonterminals: - # TODO this doesn't work for nested calls. - append += '=' + self._name.api_type name = self._name.get_public_name() if like_name: diff --git a/jedi/api/completion.py b/jedi/api/completion.py index ff8b53ef..929fb297 100644 --- a/jedi/api/completion.py +++ b/jedi/api/completion.py @@ -19,11 +19,17 @@ from jedi.inference.base_value import ValueSet from jedi.inference.helpers import infer_call_of_leaf, parse_dotted_names from jedi.inference.context import get_global_filters from jedi.inference.value import TreeInstance, ModuleValue +from jedi.inference.names import ParamNameWrapper from jedi.inference.gradual.conversion import convert_values from jedi.parser_utils import cut_value_at_position from jedi.plugins import plugin_manager +class ParamNameWithEquals(ParamNameWrapper): + def get_public_name(self): + return self.string_name + '=' + + def get_signature_param_names(signatures): # add named params for call_sig in signatures: @@ -31,7 +37,7 @@ def get_signature_param_names(signatures): # Allow protected access, because it's a public API. if p._name.get_kind() in (Parameter.POSITIONAL_OR_KEYWORD, Parameter.KEYWORD_ONLY): - yield p._name + yield ParamNameWithEquals(p._name) def filter_names(inference_state, completion_names, stack, like_name, fuzzy): diff --git a/test/completion/named_param.py b/test/completion/named_param.py index 024e2bfb..141ffe47 100644 --- a/test/completion/named_param.py +++ b/test/completion/named_param.py @@ -8,7 +8,7 @@ Named Params: def a(abc): pass -#? 5 ['abc'] +#? 5 ['abc='] a(abc) @@ -24,14 +24,14 @@ a(some_kwargs) def multiple(foo, bar): pass -#? 17 ['bar'] +#? 17 ['bar='] multiple(foo, bar) -#? ['bar'] +#? ['bar='] multiple(foo, bar my_lambda = lambda lambda_param: lambda_param + 1 -#? 22 ['lambda_param'] +#? 22 ['lambda_param='] my_lambda(lambda_param) # __call__ / __init__ @@ -45,15 +45,15 @@ class Test(object): def test(self, blub): pass -#? 10 ['hello_other'] +#? 10 ['hello_other='] Test(hello=) -#? 12 ['hello'] +#? 12 ['hello='] Test()(hello=) #? 11 [] Test()(self=) #? 16 [] Test().test(self=) -#? 16 ['blub'] +#? 16 ['blub='] Test().test(blub=) # builtins @@ -65,7 +65,7 @@ any(iterable=) def foo(xyz): pass -#? 7 ['xyz'] +#? 7 ['xyz='] foo(xyz) # No completion should be possible if it's not a simple name #? 17 [] @@ -81,11 +81,11 @@ x = " "; foo(xyz[xyz) #? 20 [] x = " "; foo(xyz[(xyz) -#? 8 ['xyz'] +#? 8 ['xyz='] @foo(xyz) def x(): pass @str -#? 8 ['xyz'] +#? 8 ['xyz='] @foo(xyz) def x(): pass diff --git a/test/test_api/test_completion.py b/test/test_api/test_completion.py index ff6c3242..39255ee4 100644 --- a/test/test_api/test_completion.py +++ b/test/test_api/test_completion.py @@ -149,6 +149,18 @@ def test_with_stmt_error_recovery(Script): assert Script('with open('') as foo: foo.\na').complete(line=1) +def test_function_param_usage(Script): + c, = Script('def func(foo_value):\n str(foo_valu').complete() + assert c.complete == 'e' + assert c.name == 'foo_value' + + c1, c2 = Script('def func(foo_value):\n func(foo_valu').complete() + assert c1.complete == 'e' + assert c1.name == 'foo_value' + assert c2.complete == 'e=' + assert c2.name == 'foo_value=' + + @pytest.mark.parametrize( 'code, has_keywords', ( ('', True), diff --git a/test/test_api/test_interpreter.py b/test/test_api/test_interpreter.py index b15215f1..1bfc3d7f 100644 --- a/test/test_api/test_interpreter.py +++ b/test/test_api/test_interpreter.py @@ -311,8 +311,8 @@ def test_param_completion(): lambd = lambda xyz: 3 - _assert_interpreter_complete('foo(bar', locals(), ['bar']) - assert bool(jedi.Interpreter('lambd(xyz', [locals()]).complete()) == is_py3 + _assert_interpreter_complete('foo(bar', locals(), ['bar=']) + _assert_interpreter_complete('lambd(xyz', locals(), ['xyz=']) def test_endless_yield(): @@ -357,7 +357,7 @@ def test_keyword_argument(): pass c, = jedi.Interpreter("f(some_keyw", [{'f': f}]).complete() - assert c.name == 'some_keyword_argument' + assert c.name == 'some_keyword_argument=' assert c.complete == 'ord_argument=' # This needs inspect.signature to work. @@ -365,7 +365,7 @@ def test_keyword_argument(): # Make it impossible for jedi to find the source of the function. f.__name__ = 'xSOMETHING' c, = jedi.Interpreter("x(some_keyw", [{'x': f}]).complete() - assert c.name == 'some_keyword_argument' + assert c.name == 'some_keyword_argument=' def test_more_complex_instances():