Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add --used-fixtures command #23

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 66 additions & 6 deletions pytest_deadfixtures.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@
"Hey there, I believe the following fixture(s) are not being used:"
)
UNUSED_FIXTURES_NOT_FOUND_HEADLINE = "Cool, every declared fixture is being used."
USED_FIXTURES_FOUND_HEADLINE = (
"Hey there, I believe the following fixture(s) are being used:"
)
USED_FIXTURES_NOT_FOUND_HEADLINE = "We could not find any fixtures being used"

EXIT_CODE_ERROR = 11
EXIT_CODE_SUCCESS = 0
Expand All @@ -23,6 +27,8 @@

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

UsedFixture = namedtuple("UsedFixture", "relpath, argname, fixturedef")


def pytest_addoption(parser):
group = parser.getgroup("deadfixtures")
Expand All @@ -40,6 +46,13 @@ def pytest_addoption(parser):
default=False,
help="Show duplicated fixtures",
)
group.addoption(
"--used-fixtures",
action="store_true",
dest="usedfixtures",
default=False,
help="Show fixtures being used",
)


def pytest_cmdline_main(config):
Expand All @@ -49,6 +62,10 @@ def pytest_cmdline_main(config):
if _show_dead_fixtures(config):
return EXIT_CODE_ERROR
return EXIT_CODE_SUCCESS
elif config.option.usedfixtures:
if _show_used_fixtures(config):
return EXIT_CODE_ERROR
return EXIT_CODE_SUCCESS


def _show_dead_fixtures(config):
Expand All @@ -57,6 +74,12 @@ def _show_dead_fixtures(config):
return wrap_session(config, show_dead_fixtures)


def _show_used_fixtures(config):
from _pytest.main import wrap_session

return wrap_session(config, show_used_fixtures)


def get_best_relpath(func, curdir):
loc = getlocation(func, curdir)
return curdir.bestrelpath(loc)
Expand Down Expand Up @@ -98,8 +121,10 @@ def get_fixtures(session):
return available


def get_used_fixturesdefs(session):
fixturesdefs = []
def get_used_fixtures(session):
used = []
seen = set()
curdir = py.path.local()
for test_function in session.items:
try:
info = test_function._fixtureinfo
Expand All @@ -113,8 +138,27 @@ def get_used_fixturesdefs(session):
for _, fixturedefs in sorted(info.name2fixturedefs.items()):
if fixturedefs is None:
continue
fixturesdefs.append(fixturedefs[-1])
return fixturesdefs

for fixturedef in fixturedefs:
loc = getlocation(fixturedef.func, curdir)
if (fixturedef.argname, loc) in seen:
continue

seen.add((fixturedef.argname, loc))

module = fixturedef.func.__module__

if (
not module.startswith("_pytest.")
and not module.startswith("pytest_")
and not ("site-packages" in loc)
):
used.append(
UsedFixture(
curdir.bestrelpath(loc), fixturedef.argname, fixturedef
)
)
return used


def write_docstring(tw, doc):
Expand Down Expand Up @@ -198,13 +242,13 @@ def show_dead_fixtures(config, session):
tw = _pytest.config.create_terminal_writer(config)
show_fixture_doc = config.getvalue("show_fixture_doc")

used_fixtures = get_used_fixturesdefs(session)
used_fixturedefs = [f.fixturedef for f in get_used_fixtures(session)]
available_fixtures = get_fixtures(session)

unused_fixtures = [
fixture
for fixture in available_fixtures
if fixture.fixturedef not in used_fixtures
if fixture.fixturedef not in used_fixturedefs
]

tw.line()
Expand All @@ -214,3 +258,19 @@ def show_dead_fixtures(config, session):
else:
tw.line(UNUSED_FIXTURES_NOT_FOUND_HEADLINE, green=True)
return unused_fixtures


def show_used_fixtures(config, session):
session.perform_collect()
tw = _pytest.config.create_terminal_writer(config)
verbose = config.getvalue("verbose")

used_fixtures = get_used_fixtures(session)

tw.line()
if used_fixtures:
tw.line(USED_FIXTURES_FOUND_HEADLINE, green=True)
write_fixtures(tw, used_fixtures, verbose)
else:
tw.line(USED_FIXTURES_NOT_FOUND_HEADLINE, red=True)
return used_fixtures
36 changes: 36 additions & 0 deletions tests/test_deadfixtures.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,11 @@ def test_simple():

assert message not in result.stdout.str()

result = pytester.runpytest("--used-fixtures")
message = message_template.format("autouse_fixture", "test_dont_list_autouse_fixture")

assert message in result.stdout.str()


def test_dont_list_same_file_fixture(pytester, message_template):
pytester.makepyfile(
Expand All @@ -90,6 +95,13 @@ def test_simple(same_file_fixture):

assert message not in result.stdout.str()

result = pytester.runpytest("--used-fixtures")
message = message_template.format(
"same_file_fixture", "test_dont_list_same_file_fixture"
)

assert message in result.stdout.str()


def test_list_same_file_unused_fixture(pytester, message_template):
pytester.makepyfile(
Expand All @@ -114,6 +126,13 @@ def test_simple():

assert message in result.stdout.str()

result = pytester.runpytest("--used-fixtures")
message = message_template.format(
"same_file_fixture", "test_list_same_file_unused_fixture"
)

assert message not in result.stdout.str()


def test_list_same_file_multiple_unused_fixture(pytester, message_template):
pytester.makepyfile(
Expand Down Expand Up @@ -176,6 +195,11 @@ def test_conftest_fixture(conftest_fixture):

assert message not in result.stdout.str()

result = pytester.runpytest("--used-fixtures")
message = message_template.format("conftest_fixture", "conftest")

assert message in result.stdout.str()


def test_list_conftest_unused_fixture(pytester, message_template):
pytester.makepyfile(
Expand Down Expand Up @@ -204,6 +228,11 @@ def test_conftest_fixture():

assert message in result.stdout.str()

result = pytester.runpytest("--used-fixtures")
message = message_template.format("conftest_fixture", "conftest")

assert message not in result.stdout.str()


def test_list_conftest_multiple_unused_fixture(pytester, message_template):
pytester.makepyfile(
Expand Down Expand Up @@ -266,6 +295,13 @@ def test_decorator_usefixtures():

assert message not in result.stdout.str()

result = pytester.runpytest("--used-fixtures")
message = message_template.format(
"decorator_usefixtures", "test_dont_list_decorator_usefixtures"
)

assert message in result.stdout.str()


def test_write_docs_when_verbose(pytester):
pytester.makepyfile(
Expand Down