Skip to content

Commit 97fdb2b

Browse files
Add --used-fixtures command
1 parent e7d25cc commit 97fdb2b

File tree

2 files changed

+114
-6
lines changed

2 files changed

+114
-6
lines changed

pytest_deadfixtures.py

Lines changed: 66 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@
1515
"Hey there, I believe the following fixture(s) are not being used:"
1616
)
1717
UNUSED_FIXTURES_NOT_FOUND_HEADLINE = "Cool, every declared fixture is being used."
18+
USED_FIXTURES_FOUND_HEADLINE = (
19+
"Hey there, I believe the following fixture(s) are being used:"
20+
)
21+
USED_FIXTURES_NOT_FOUND_HEADLINE = "We could not find any fixtures being used"
1822

1923
EXIT_CODE_ERROR = 11
2024
EXIT_CODE_SUCCESS = 0
@@ -23,6 +27,8 @@
2327

2428
CachedFixture = namedtuple("CachedFixture", "fixturedef, relpath, result")
2529

30+
UsedFixture = namedtuple('UsedFixture', 'relpath, argname, fixturedef')
31+
2632

2733
def pytest_addoption(parser):
2834
group = parser.getgroup("deadfixtures")
@@ -40,6 +46,13 @@ def pytest_addoption(parser):
4046
default=False,
4147
help="Show duplicated fixtures",
4248
)
49+
group.addoption(
50+
'--used-fixtures',
51+
action='store_true',
52+
dest='usedfixtures',
53+
default=False,
54+
help='Show fixtures being used',
55+
)
4356

4457

4558
def pytest_cmdline_main(config):
@@ -49,6 +62,10 @@ def pytest_cmdline_main(config):
4962
if _show_dead_fixtures(config):
5063
return EXIT_CODE_ERROR
5164
return EXIT_CODE_SUCCESS
65+
elif config.option.usedfixtures:
66+
if _show_used_fixtures(config):
67+
return EXIT_CODE_ERROR
68+
return EXIT_CODE_SUCCESS
5269

5370

5471
def _show_dead_fixtures(config):
@@ -57,6 +74,12 @@ def _show_dead_fixtures(config):
5774
return wrap_session(config, show_dead_fixtures)
5875

5976

77+
def _show_used_fixtures(config):
78+
from _pytest.main import wrap_session
79+
80+
return wrap_session(config, show_used_fixtures)
81+
82+
6083
def get_best_relpath(func, curdir):
6184
loc = getlocation(func, curdir)
6285
return curdir.bestrelpath(loc)
@@ -98,8 +121,10 @@ def get_fixtures(session):
98121
return available
99122

100123

101-
def get_used_fixturesdefs(session):
102-
fixturesdefs = []
124+
def get_used_fixtures(session):
125+
used = []
126+
seen = set()
127+
curdir = py.path.local()
103128
for test_function in session.items:
104129
try:
105130
info = test_function._fixtureinfo
@@ -113,8 +138,27 @@ def get_used_fixturesdefs(session):
113138
for _, fixturedefs in sorted(info.name2fixturedefs.items()):
114139
if fixturedefs is None:
115140
continue
116-
fixturesdefs.append(fixturedefs[-1])
117-
return fixturesdefs
141+
142+
for fixturedef in fixturedefs:
143+
loc = getlocation(fixturedef.func, curdir)
144+
if (fixturedef.argname, loc) in seen:
145+
continue
146+
147+
seen.add((fixturedef.argname, loc))
148+
149+
module = fixturedef.func.__module__
150+
151+
if (
152+
not module.startswith("_pytest.")
153+
and not module.startswith("pytest_")
154+
and not ('site-packages' in loc)
155+
):
156+
used.append(
157+
UsedFixture(
158+
curdir.bestrelpath(loc), fixturedef.argname, fixturedef
159+
)
160+
)
161+
return used
118162

119163

120164
def write_docstring(tw, doc):
@@ -198,13 +242,13 @@ def show_dead_fixtures(config, session):
198242
tw = _pytest.config.create_terminal_writer(config)
199243
show_fixture_doc = config.getvalue("show_fixture_doc")
200244

201-
used_fixtures = get_used_fixturesdefs(session)
245+
used_fixturedefs = [f.fixturedef for f in get_used_fixtures(session)]
202246
available_fixtures = get_fixtures(session)
203247

204248
unused_fixtures = [
205249
fixture
206250
for fixture in available_fixtures
207-
if fixture.fixturedef not in used_fixtures
251+
if fixture.fixturedef not in used_fixturedefs
208252
]
209253

210254
tw.line()
@@ -214,3 +258,19 @@ def show_dead_fixtures(config, session):
214258
else:
215259
tw.line(UNUSED_FIXTURES_NOT_FOUND_HEADLINE, green=True)
216260
return unused_fixtures
261+
262+
263+
def show_used_fixtures(config, session):
264+
session.perform_collect()
265+
tw = _pytest.config.create_terminal_writer(config)
266+
verbose = config.getvalue('verbose')
267+
268+
used_fixtures = get_used_fixtures(session)
269+
270+
tw.line()
271+
if used_fixtures:
272+
tw.line(USED_FIXTURES_FOUND_HEADLINE, green=True)
273+
write_fixtures(tw, used_fixtures, verbose)
274+
else:
275+
tw.line(USED_FIXTURES_NOT_FOUND_HEADLINE, red=True)
276+
return used_fixtures

tests/test_deadfixtures.py

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,14 @@ def test_simple():
6666

6767
assert message not in result.stdout.str()
6868

69+
result = pytester.runpytest('--used-fixtures')
70+
message = message_template.format(
71+
'autouse_fixture',
72+
'test_dont_list_autouse_fixture'
73+
)
74+
75+
assert message in result.stdout.str()
76+
6977

7078
def test_dont_list_same_file_fixture(pytester, message_template):
7179
pytester.makepyfile(
@@ -90,6 +98,14 @@ def test_simple(same_file_fixture):
9098

9199
assert message not in result.stdout.str()
92100

101+
result = pytester.runpytest('--used-fixtures')
102+
message = message_template.format(
103+
'same_file_fixture',
104+
'test_dont_list_same_file_fixture'
105+
)
106+
107+
assert message in result.stdout.str()
108+
93109

94110
def test_list_same_file_unused_fixture(pytester, message_template):
95111
pytester.makepyfile(
@@ -114,6 +130,14 @@ def test_simple():
114130

115131
assert message in result.stdout.str()
116132

133+
result = pytester.runpytest('--used-fixtures')
134+
message = message_template.format(
135+
'same_file_fixture',
136+
'test_list_same_file_unused_fixture'
137+
)
138+
139+
assert message not in result.stdout.str()
140+
117141

118142
def test_list_same_file_multiple_unused_fixture(pytester, message_template):
119143
pytester.makepyfile(
@@ -176,6 +200,14 @@ def test_conftest_fixture(conftest_fixture):
176200

177201
assert message not in result.stdout.str()
178202

203+
result = pytester.runpytest('--used-fixtures')
204+
message = message_template.format(
205+
'conftest_fixture',
206+
'conftest'
207+
)
208+
209+
assert message in result.stdout.str()
210+
179211

180212
def test_list_conftest_unused_fixture(pytester, message_template):
181213
pytester.makepyfile(
@@ -204,6 +236,14 @@ def test_conftest_fixture():
204236

205237
assert message in result.stdout.str()
206238

239+
result = pytester.runpytest('--used-fixtures')
240+
message = message_template.format(
241+
'conftest_fixture',
242+
'conftest'
243+
)
244+
245+
assert message not in result.stdout.str()
246+
207247

208248
def test_list_conftest_multiple_unused_fixture(pytester, message_template):
209249
pytester.makepyfile(
@@ -266,6 +306,14 @@ def test_decorator_usefixtures():
266306

267307
assert message not in result.stdout.str()
268308

309+
result = pytester.runpytest('--used-fixtures')
310+
message = message_template.format(
311+
'decorator_usefixtures',
312+
'test_dont_list_decorator_usefixtures'
313+
)
314+
315+
assert message in result.stdout.str()
316+
269317

270318
def test_write_docs_when_verbose(pytester):
271319
pytester.makepyfile(

0 commit comments

Comments
 (0)