diff --git a/CHANGELOG.md b/CHANGELOG.md index 699c69c..5436338 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,9 @@ ## [Unreleased] +### Added +- Suppressing FP `unused-import` when fixtures defined elsewhere are imported into `conftest.py` but not directly used (#2) + ## [1.0.0] - 2021-03-02 ### Added - Python 3.9 support diff --git a/pylint_pytest/checkers/fixture.py b/pylint_pytest/checkers/fixture.py index feb80c5..e34fac1 100644 --- a/pylint_pytest/checkers/fixture.py +++ b/pylint_pytest/checkers/fixture.py @@ -71,10 +71,14 @@ def visit_module(self, node): # run pytest session with customized plugin to collect fixtures fixture_collector = FixtureCollector() + + # save and restore sys.path to prevent pytest.main from altering it + sys_path = sys.path.copy() pytest.main( [node.file, '--fixtures', '--collect-only'], plugins=[fixture_collector], ) + sys.path = sys_path FixtureChecker._pytest_fixtures = fixture_collector.fixtures finally: # restore output devices @@ -118,6 +122,13 @@ def patch_add_message(self, msgid, line=None, node=None, args=None, if message_tokens[0] == 'import' and len(message_tokens) == 2: pass + # fixture is defined in other modules and being imported to + # conftest for pytest magic + elif isinstance(node.parent, astroid.Module) \ + and node.parent.name.split('.')[-1] == 'conftest' \ + and fixture_name in FixtureChecker._pytest_fixtures: + return + # imported fixture is referenced in test/fixture func elif fixture_name in FixtureChecker._invoked_with_func_args \ and fixture_name in FixtureChecker._pytest_fixtures: diff --git a/tests/base_tester.py b/tests/base_tester.py index c188e19..8c1cedd 100644 --- a/tests/base_tester.py +++ b/tests/base_tester.py @@ -30,23 +30,22 @@ def run_linter(self, enable_plugin, file_path=None): with open(file_path) as fin: content = fin.read() - module = astroid.parse(content) + module = astroid.parse(content, module_name=module) module.file = fin.name self.walk(module) # run all checkers - BasePytestTester.MESSAGES = self.linter.release_messages() + self.MESSAGES = self.linter.release_messages() def verify_messages(self, msg_count, msg_id=None): msg_id = msg_id or self.MSG_ID matched_count = 0 for message in self.MESSAGES: - print(message) # only care about ID and count, not the content if message.msg_id == msg_id: matched_count += 1 - assert matched_count == msg_count + assert matched_count == msg_count, f'expecting {msg_count}, actual {matched_count}' def setup_method(self): self.linter = UnittestLinter() diff --git a/tests/input/unused-import/_fixture_for_conftest.py b/tests/input/unused-import/_fixture_for_conftest.py new file mode 100644 index 0000000..c968940 --- /dev/null +++ b/tests/input/unused-import/_fixture_for_conftest.py @@ -0,0 +1,6 @@ +import pytest + + +@pytest.fixture +def conftest_fixture_attr(): + return True diff --git a/tests/input/unused-import/conftest.py b/tests/input/unused-import/conftest.py new file mode 100644 index 0000000..daecf90 --- /dev/null +++ b/tests/input/unused-import/conftest.py @@ -0,0 +1 @@ +from _fixture_for_conftest import conftest_fixture_attr diff --git a/tests/test_unused_import.py b/tests/test_unused_import.py index 2d47f0c..888e432 100644 --- a/tests/test_unused_import.py +++ b/tests/test_unused_import.py @@ -32,3 +32,10 @@ def test_same_name_decorator(self, enable_plugin): name as fixture - should still raise unused-import warning''' self.run_linter(enable_plugin) self.verify_messages(1) + + @pytest.mark.parametrize('enable_plugin', [True, False]) + def test_conftest(self, enable_plugin): + '''fixtures are defined in different modules and imported to conftest + for pytest to do its magic''' + self.run_linter(enable_plugin) + self.verify_messages(0 if enable_plugin else 1)