diff --git a/pylint_pytest/checkers/fixture.py b/pylint_pytest/checkers/fixture.py index 32ec894..91c2af8 100644 --- a/pylint_pytest/checkers/fixture.py +++ b/pylint_pytest/checkers/fixture.py @@ -116,10 +116,10 @@ def visit_module(self, node): is_test_module = True break + stdout, stderr = sys.stdout, sys.stderr try: with open(os.devnull, "w") as devnull: # suppress any future output from pytest - stdout, stderr = sys.stdout, sys.stderr sys.stderr = sys.stdout = devnull # run pytest session with customized plugin to collect fixtures @@ -210,7 +210,7 @@ def visit_functiondef(self, node): for arg in node.args.args: self._invoked_with_func_args.add(arg.name) - # pylint: disable=bad-staticmethod-argument + # pylint: disable=bad-staticmethod-argument,too-many-branches # The function itself is an if-return logic. @staticmethod def patch_add_message( self, msgid, line=None, node=None, args=None, confidence=None, col_offset=None @@ -267,9 +267,18 @@ def patch_add_message( msgid == "unused-argument" and _can_use_fixture(node.parent.parent) and isinstance(node.parent, astroid.Arguments) - and node.name in FixtureChecker._pytest_fixtures ): - return + if node.name in FixtureChecker._pytest_fixtures: + # argument is used as a fixture + return + + fixnames = ( + arg.name for arg in node.parent.args if arg.name in FixtureChecker._pytest_fixtures + ) + for fixname in fixnames: + if node.name in FixtureChecker._pytest_fixtures[fixname][0].argnames: + # argument is used by a fixture + return # check W0621 redefined-outer-name if ( diff --git a/tests/input/unused-argument/func_param_as_fixture_arg.py b/tests/input/unused-argument/func_param_as_fixture_arg.py new file mode 100644 index 0000000..003d194 --- /dev/null +++ b/tests/input/unused-argument/func_param_as_fixture_arg.py @@ -0,0 +1,31 @@ +""" +This module illustrates a situation in which unused-argument should be +suppressed, but is not. +""" + +import pytest + + +@pytest.fixture +def myfix(arg): + """A fixture that requests a function param""" + print("arg is ", arg) + return True + + +@pytest.mark.parametrize("arg", [1, 2, 3]) +def test_myfix(myfix, arg): + """A test function that uses the param through a fixture""" + assert myfix + + +@pytest.mark.parametrize("narg", [4, 5, 6]) +def test_nyfix(narg): # unused-argument + """A test function that does not use its param""" + assert True + + +@pytest.mark.parametrize("arg", [1, 2, 3]) +def test_narg_is_used_nowhere(myfix, narg): + """A test function that uses the param through a fixture""" + assert myfix diff --git a/tests/test_unused_argument.py b/tests/test_unused_argument.py index 7ca2307..a164672 100644 --- a/tests/test_unused_argument.py +++ b/tests/test_unused_argument.py @@ -29,3 +29,8 @@ def test_caller_not_a_test_func(self, enable_plugin): def test_args_and_kwargs(self, enable_plugin): self.run_linter(enable_plugin) self.verify_messages(2) + + @pytest.mark.parametrize("enable_plugin", [True, False]) + def test_func_param_as_fixture_arg(self, enable_plugin): + self.run_linter(enable_plugin) + self.verify_messages(2 if enable_plugin else 3)