diff --git a/jedi/api/completion.py b/jedi/api/completion.py index 1b43657b..0602244b 100644 --- a/jedi/api/completion.py +++ b/jedi/api/completion.py @@ -76,7 +76,7 @@ def get_flow_scope_node(module_node, position): @plugin_manager.decorate() -def complete_param_names(context, function_name): +def complete_param_names(context, function_name, decorator_nodes): # Basically there's no way to do param completion. The plugins are # responsible for this. return [] @@ -225,14 +225,7 @@ class Completion: dot = self._module_node.get_leaf_for_position(self._position) completion_names += self._complete_trailer(dot.get_previous_leaf()) elif self._is_parameter_completion(): - stack_node = self.stack[-2] - if stack_node.nonterminal == 'parameters': - stack_node = self.stack[-3] - if stack_node.nonterminal == 'funcdef': - context = get_user_context(self._module_context, self._position) - function_name = stack_node.nodes[1] - - completion_names += complete_param_names(context, function_name) + completion_names += self._complete_params(leaf) else: completion_names += self._complete_global_scope() completion_names += self._complete_inherited(is_function=False) @@ -264,6 +257,28 @@ class Completion: # var args is for lambdas and typed args for normal functions return tos.nonterminal in ('typedargslist', 'varargslist') and tos.nodes[-1] == ',' + def _complete_params(self, leaf): + stack_node = self.stack[-2] + if stack_node.nonterminal == 'parameters': + stack_node = self.stack[-3] + if stack_node.nonterminal == 'funcdef': + context = get_user_context(self._module_context, self._position) + node = search_ancestor(leaf, 'error_node', 'funcdef') + if node.type == 'error_node': + n = node.children[0] + if n.type == 'decorators': + decorators = n.children + elif n.type == 'decorator': + decorators = [n] + else: + decorators = [] + else: + decorators = node.get_decorators() + function_name = stack_node.nodes[1] + + return complete_param_names(context, function_name.value, decorators) + return [] + def _complete_keywords(self, allowed_transitions): for k in allowed_transitions: if isinstance(k, str) and k.isalpha(): diff --git a/jedi/plugins/pytest.py b/jedi/plugins/pytest.py index b4e6d579..7ae2194d 100644 --- a/jedi/plugins/pytest.py +++ b/jedi/plugins/pytest.py @@ -54,14 +54,16 @@ def goto_anonymous_param(func): def complete_param_names(func): - def wrapper(context, func_name): + def wrapper(context, func_name, decorator_nodes): module_context = context.get_root_context() - names = [] - for module_context in _iter_pytest_modules(module_context): - names += FixtureFilter(module_context).values() - if names: - return names - return func(context, func_name) + if func_name.startswith('test_') \ + or any('fixture' in n.get_code() for n in decorator_nodes): + names = [] + for module_context in _iter_pytest_modules(module_context): + names += FixtureFilter(module_context).values() + if names: + return names + return func(context, func_name, decorator_nodes) return wrapper diff --git a/test/completion/pytest.py b/test/completion/pytest.py index b6f8adca..345fa34d 100644 --- a/test/completion/pytest.py +++ b/test/completion/pytest.py @@ -72,3 +72,29 @@ def test_x(my_con #? 18 ['my_conftest_fixture'] def test_x(my_conftest_fixture): return + +#? [] +def lala(my_con + return + +@pytest.fixture +#? ['my_conftest_fixture'] +def lala(my_con + return + +@pytest.fixture +#? 15 ['my_conftest_fixture'] +def lala(my_con): + return + +@pytest.fixture +@some_decorator +#? ['my_conftest_fixture'] +def lala(my_con + return + +@pytest.fixture +@some_decorator +#? 15 ['my_conftest_fixture'] +def lala(my_con): + return