Skip to content
This repository was archived by the owner on Apr 29, 2024. It is now read-only.

Commit 4f82aff

Browse files
committed
Improve F6401: cannot-enumerate-pytest-fixtures:
* Capture and return `stdout` and `stderr` (instead of trashing them) * Fix the 'duplicate-path' error by `relative`-izing the paths before `union`ing them * Update tests to test for both conditions Additionally: * `pylint-pytest` does not support `pylint>=3` * Fix two `used-before-assignment` pylint issues (`stdout`, `stderr`) 🤪 Signed-off-by: Stavros Ntentos <[email protected]>
1 parent 5fc5dee commit 4f82aff

File tree

3 files changed

+52
-8
lines changed

3 files changed

+52
-8
lines changed

pylint_pytest/checkers/fixture.py

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import io
12
import os
23
import sys
34
from pathlib import Path
@@ -61,7 +62,7 @@ class FixtureChecker(BasePytestChecker):
6162
'F6401': (
6263
(
6364
'pylint-pytest plugin cannot enumerate and collect pytest fixtures. '
64-
'Please run `pytest --fixtures --collect-only %s` and resolve any potential syntax error or package dependency issues'
65+
'Please run `pytest --fixtures --collect-only %s` and resolve any potential syntax error or package dependency issues. stdout: %s. stderr: %s.'
6566
),
6667
'cannot-enumerate-pytest-fixtures',
6768
'Used when pylint-pytest has been unable to enumerate and collect pytest fixtures.',
@@ -110,11 +111,12 @@ def visit_module(self, node):
110111
is_test_module = True
111112
break
112113

114+
stdout, stderr = sys.stdout, sys.stderr
113115
try:
114-
with open(os.devnull, 'w') as devnull:
116+
with (io.StringIO() as captured_stdout, io.StringIO() as captured_stderr):
115117
# suppress any future output from pytest
116-
stdout, stderr = sys.stdout, sys.stderr
117-
sys.stderr = sys.stdout = devnull
118+
sys.stderr = captured_stderr
119+
sys.stdout = captured_stdout
118120

119121
# run pytest session with customized plugin to collect fixtures
120122
fixture_collector = FixtureCollector()
@@ -146,9 +148,17 @@ def visit_module(self, node):
146148
)
147149
)
148150
if (ret != pytest.ExitCode.OK or legitimate_failure_paths) and is_test_module:
151+
files_to_report = {
152+
str(Path(x).absolute().relative_to(Path.cwd())) for x in legitimate_failure_paths | {node.file}
153+
}
154+
149155
self.add_message(
150156
'cannot-enumerate-pytest-fixtures',
151-
args=' '.join(legitimate_failure_paths | {node.file}),
157+
args=(
158+
' '.join(files_to_report),
159+
captured_stdout.getvalue(),
160+
captured_stderr.getvalue(),
161+
),
152162
node=node,
153163
)
154164
finally:

setup.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#!/usr/bin/env python
1+
#!/usr/bin/env python3
22
# -*- coding: utf-8 -*-
33

44
from os import path
@@ -24,7 +24,7 @@
2424
long_description_content_type='text/markdown',
2525
packages=find_packages(exclude=['tests', 'sandbox']),
2626
install_requires=[
27-
'pylint',
27+
'pylint<3',
2828
'pytest>=4.6',
2929
],
3030
python_requires='>=3.6',

tests/test_cannot_enumerate_fixtures.py

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1+
import re
2+
13
import pytest
2-
from pylint.checkers.variables import VariablesChecker
4+
35
from base_tester import BasePytestTester
46
from pylint_pytest.checkers.fixture import FixtureChecker
57

@@ -13,7 +15,39 @@ def test_no_such_package(self, enable_plugin):
1315
self.run_linter(enable_plugin)
1416
self.verify_messages(1 if enable_plugin else 0)
1517

18+
if enable_plugin:
19+
msg = self.MESSAGES[0]
20+
21+
# Asserts/Fixes duplicate filenames in output:
22+
# https://github.com/reverbc/pylint-pytest/pull/22/files#r698204470
23+
filename_arg = msg.args[0]
24+
assert len(re.findall(r"\.py", filename_arg)) == 1
25+
26+
# Asserts that path is relative (usually to the root of the repository).
27+
assert filename_arg[0] != "/"
28+
29+
# Assert `stdout` is non-empty.
30+
assert msg.args[1]
31+
# Assert `stderr` is empty (pytest runs stably, even though fixture collection fails).
32+
assert not msg.args[2]
33+
1634
@pytest.mark.parametrize('enable_plugin', [True, False])
1735
def test_import_corrupted_module(self, enable_plugin):
1836
self.run_linter(enable_plugin)
1937
self.verify_messages(1 if enable_plugin else 0)
38+
39+
if enable_plugin:
40+
msg = self.MESSAGES[0]
41+
42+
# ... somehow, since `import_corrupted_module.py` imports `no_such_package.py`
43+
# both of their names are returned in the message.
44+
filename_arg = msg.args[0]
45+
assert len(re.findall(r"\.py", filename_arg)) == 2
46+
47+
# Asserts that paths are relative (usually to the root of the repository).
48+
assert not [x for x in filename_arg.split(' ') if x[0] == "/"]
49+
50+
# Assert `stdout` is non-empty.
51+
assert msg.args[1]
52+
# Assert `stderr` is empty (pytest runs stably, even though fixture collection fails).
53+
assert not msg.args[2]

0 commit comments

Comments
 (0)