From 0d15347210dda2306e34fdd3c9c9b8b437b075a3 Mon Sep 17 00:00:00 2001 From: Peter Law Date: Sat, 24 Jul 2021 16:14:20 +0100 Subject: [PATCH 1/4] Remove confusing comment I'm assuming that this is incorrect given that there _are_ arguments where the comment suggests there aren't any. --- test/test_inference/test_signature.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/test/test_inference/test_signature.py b/test/test_inference/test_signature.py index 85adaff7..a4df83c3 100644 --- a/test/test_inference/test_signature.py +++ b/test/test_inference/test_signature.py @@ -273,8 +273,6 @@ def test_pow_signature(Script, environment): def x(f): @functools.wraps(f) def wrapper(*args): - # Have no arguments here, but because of wraps, the signature - # should still be f's. return f(*args) return wrapper From bb40390225b9723ea92851a6cc4a412f3c2fb669 Mon Sep 17 00:00:00 2001 From: Peter Law Date: Sat, 24 Jul 2021 16:15:05 +0100 Subject: [PATCH 2/4] Add identifiers to these test strings This makes it easier to work out which one fails when pytest reports a failure. Mostly useful when introducing failing tests, which I'm about to do. --- test/test_inference/test_signature.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/test_inference/test_signature.py b/test/test_inference/test_signature.py index a4df83c3..beb405ca 100644 --- a/test/test_inference/test_signature.py +++ b/test/test_inference/test_signature.py @@ -267,6 +267,7 @@ def test_pow_signature(Script, environment): @pytest.mark.parametrize( 'code, signature', [ [dedent(''' + # identifier:A import functools def f(x): pass @@ -278,6 +279,7 @@ def test_pow_signature(Script, environment): x(f)('''), 'f(x, /)'], [dedent(''' + # identifier:B import functools def f(x): pass From 6787719c2839f98a32b97b7eab564da35d154b2b Mon Sep 17 00:00:00 2001 From: Peter Law Date: Sat, 24 Jul 2021 16:16:45 +0100 Subject: [PATCH 3/4] Ensure *args, **kwargs lookthrough works at module scope too This means that passthrough signatures will be found for top level functions, which is useful both where they're wrappered by `functools.wraps` or not. Fixes https://github.com/davidhalter/jedi/issues/1791. --- jedi/inference/star_args.py | 10 +++++++++- test/test_inference/test_signature.py | 20 ++++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/jedi/inference/star_args.py b/jedi/inference/star_args.py index 521cd4eb..0c3a9e53 100644 --- a/jedi/inference/star_args.py +++ b/jedi/inference/star_args.py @@ -22,7 +22,15 @@ def _iter_nodes_for_param(param_name): from jedi.inference.arguments import TreeArguments execution_context = param_name.parent_context - function_node = execution_context.tree_node + # Walk up the parso tree to get the FunctionNode we want. We use the parso + # tree rather than going via the execution context so that we're agnostic of + # the specific scope we're evaluating within (i.e: module or function, + # etc.). + # - .tree_name is a Name + # - .parent is a Param + # - .parent is a PythonNode(parameters) + # - .parent is the FunctionNode we want. + function_node = param_name.tree_name.parent.parent.parent module_node = function_node.get_root_node() start = function_node.children[-1].start_pos end = function_node.children[-1].end_pos diff --git a/test/test_inference/test_signature.py b/test/test_inference/test_signature.py index beb405ca..9ee8a55c 100644 --- a/test/test_inference/test_signature.py +++ b/test/test_inference/test_signature.py @@ -292,6 +292,26 @@ def test_pow_signature(Script, environment): return wrapper x(f)('''), 'f()'], + [dedent(''' + # identifier:C + import functools + def f(x: int, y: float): + pass + + @functools.wraps(f) + def wrapper(*args, **kwargs): + return f(*args, **kwargs) + + wrapper('''), 'f(x: int, y: float)'], + [dedent(''' + # identifier:D + def f(x: int, y: float): + pass + + def wrapper(*args, **kwargs): + return f(*args, **kwargs) + + wrapper('''), 'wrapper(x: int, y: float)'], ] ) def test_wraps_signature(Script, code, signature): From ab2eb570a81922546f7c870f2d3c34878a55f642 Mon Sep 17 00:00:00 2001 From: Peter Law Date: Sat, 24 Jul 2021 17:27:27 +0100 Subject: [PATCH 4/4] Use search_ancestor for a more robust search --- jedi/inference/star_args.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/jedi/inference/star_args.py b/jedi/inference/star_args.py index 0c3a9e53..71ea7093 100644 --- a/jedi/inference/star_args.py +++ b/jedi/inference/star_args.py @@ -12,6 +12,8 @@ The signature here for bar should be `bar(b, c)` instead of bar(*args). """ from inspect import Parameter +from parso import tree + from jedi.inference.utils import to_list from jedi.inference.names import ParamNameWrapper from jedi.inference.helpers import is_big_annoying_library @@ -26,11 +28,7 @@ def _iter_nodes_for_param(param_name): # tree rather than going via the execution context so that we're agnostic of # the specific scope we're evaluating within (i.e: module or function, # etc.). - # - .tree_name is a Name - # - .parent is a Param - # - .parent is a PythonNode(parameters) - # - .parent is the FunctionNode we want. - function_node = param_name.tree_name.parent.parent.parent + function_node = tree.search_ancestor(param_name.tree_name, 'funcdef', 'lambdef') module_node = function_node.get_root_node() start = function_node.children[-1].start_pos end = function_node.children[-1].end_pos