diff --git a/_pytest/python.py b/_pytest/python.py index e7bb9ad62..6c130f93e 100644 --- a/_pytest/python.py +++ b/_pytest/python.py @@ -979,50 +979,48 @@ def _show_fixtures_per_test(config, session): tw = _pytest.config.create_terminal_writer(config) verbose = config.getvalue("verbose") - def get_best_rel(func): + def get_best_relpath(func): loc = getlocation(func, curdir) return curdir.bestrelpath(loc) def write_fixture(fixture_def): argname = fixture_def.argname - if verbose <= 0 and argname.startswith("_"): return if verbose > 0: - bestrel = get_best_rel(fixture_def.func) + bestrel = get_best_relpath(fixture_def.func) funcargspec = "{0} -- {1}".format(argname, bestrel) else: funcargspec = argname tw.line(funcargspec, green=True) - fixture_doc = fixture_def.func.__doc__ - if fixture_doc: write_docstring(tw, fixture_doc) else: tw.line(' no docstring available', red=True) def write_item(item): - name2fixturedefs = item._fixtureinfo.name2fixturedefs - - if not name2fixturedefs: - # The given test item does not use any fixtures + try: + info = item._fixtureinfo + except AttributeError: + # doctests items have no _fixtureinfo attribute + return + if not info.name2fixturedefs: + # this test item does not use any fixtures return - bestrel = get_best_rel(item.function) - tw.line() tw.sep('-', 'fixtures used by {0}'.format(item.name)) - tw.sep('-', '({0})'.format(bestrel)) - for argname, fixture_defs in sorted(name2fixturedefs.items()): - assert fixture_defs is not None - if not fixture_defs: + tw.sep('-', '({0})'.format(get_best_relpath(item.function))) + # dict key not used in loop but needed for sorting + for _, fixturedefs in sorted(info.name2fixturedefs.items()): + assert fixturedefs is not None + if not fixturedefs: continue - # The last fixture def item in the list is expected - # to be the one used by the test item - write_fixture(fixture_defs[-1]) + # last item is expected to be the one used by the test item + write_fixture(fixturedefs[-1]) - for item in session.items: - write_item(item) + for session_item in session.items: + write_item(session_item) def showfixtures(config): diff --git a/changelog/2788.bugfix b/changelog/2788.bugfix new file mode 100644 index 000000000..4069bb6e6 --- /dev/null +++ b/changelog/2788.bugfix @@ -0,0 +1 @@ +When running ``pytest --fixtures-per-test``: don't crash if an item has no _fixtureinfo attribute (e.g. doctests) diff --git a/testing/python/show_fixtures_per_test.py b/testing/python/show_fixtures_per_test.py index 18563e818..741f33946 100644 --- a/testing/python/show_fixtures_per_test.py +++ b/testing/python/show_fixtures_per_test.py @@ -135,3 +135,24 @@ def test_verbose_include_private_fixtures_and_loc(testdir): 'arg3 -- test_verbose_include_private_fixtures_and_loc.py:3', ' arg3 from testmodule', ]) + + +def test_doctest_items(testdir): + testdir.makepyfile(''' + def foo(): + """ + >>> 1 + 1 + 2 + """ + ''') + testdir.maketxtfile(''' + >>> 1 + 1 + 2 + ''') + result = testdir.runpytest("--fixtures-per-test", "--doctest-modules", + "--doctest-glob=*.txt", "-v") + assert result.ret == 0 + + result.stdout.fnmatch_lines([ + '*collected 2 items*', + ])