From c516dba69a05477c002996aaf87561883dc82ad1 Mon Sep 17 00:00:00 2001 From: Rahul Kumaresan Date: Fri, 14 May 2021 18:08:55 +0530 Subject: [PATCH] add feature to view fixture source location in invocations with --fixtures-per-test option (#8626) * add feature to view fixture source location in invocations with --fixtures-per-test option * remove unrelated changes to show_fixtures_per_test::test_doctest_items * eshew the extraneous else in _show_fixtures_per_test.write_fixture * enable the accommodation of multi-line docstring with --fixtures-per-test option * add feature to view fixture source location in invocations with --fixtures * add colour encoding to fixture location paths * add changelog for #8606 fixing * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- changelog/8606.feature.rst | 5 ++ src/_pytest/python.py | 23 +++---- testing/python/fixtures.py | 26 +++---- testing/python/show_fixtures_per_test.py | 87 +++++++++++++++++++++--- 4 files changed, 108 insertions(+), 33 deletions(-) create mode 100644 changelog/8606.feature.rst diff --git a/changelog/8606.feature.rst b/changelog/8606.feature.rst new file mode 100644 index 000000000..9705ffe75 --- /dev/null +++ b/changelog/8606.feature.rst @@ -0,0 +1,5 @@ +pytest invocations with ``--fixtures-per-test`` and ``--fixtures`` have been enabled with: + +- Fixture location path printed with the fixture name. +- First section of the fixture's docstring printed under the fixture name. +- Whole of fixture's docstring printed under the fixture name using ``--verbose`` option. diff --git a/src/_pytest/python.py b/src/_pytest/python.py index 5ef5085c7..436f463ee 100644 --- a/src/_pytest/python.py +++ b/src/_pytest/python.py @@ -1428,15 +1428,15 @@ def _show_fixtures_per_test(config: Config, session: Session) -> None: argname = fixture_def.argname if verbose <= 0 and argname.startswith("_"): return - if verbose > 0: - bestrel = get_best_relpath(fixture_def.func) - funcargspec = f"{argname} -- {bestrel}" - else: - funcargspec = argname - tw.line(funcargspec, green=True) + bestrel = get_best_relpath(fixture_def.func) + tw.write(f"{argname}", green=True) + tw.write(f" -- {bestrel}", yellow=True) + tw.write("\n") fixture_doc = inspect.getdoc(fixture_def.func) if fixture_doc: - write_docstring(tw, fixture_doc) + write_docstring( + tw, fixture_doc.split("\n\n")[0] if verbose <= 0 else fixture_doc + ) else: tw.line(" no docstring available", red=True) @@ -1508,18 +1508,17 @@ def _showfixtures_main(config: Config, session: Session) -> None: tw.line() tw.sep("-", f"fixtures defined from {module}") currentmodule = module - if verbose <= 0 and argname[0] == "_": + if verbose <= 0 and argname.startswith("_"): continue - tw.write(argname, green=True) + tw.write(f"{argname}", green=True) if fixturedef.scope != "function": tw.write(" [%s scope]" % fixturedef.scope, cyan=True) - if verbose > 0: - tw.write(" -- %s" % bestrel, yellow=True) + tw.write(f" -- {bestrel}", yellow=True) tw.write("\n") loc = getlocation(fixturedef.func, str(curdir)) doc = inspect.getdoc(fixturedef.func) if doc: - write_docstring(tw, doc) + write_docstring(tw, doc.split("\n\n")[0] if verbose <= 0 else doc) else: tw.line(f" {loc}: no docstring available", red=True) tw.line() diff --git a/testing/python/fixtures.py b/testing/python/fixtures.py index 569b5d67e..b7f5b25c5 100644 --- a/testing/python/fixtures.py +++ b/testing/python/fixtures.py @@ -3334,9 +3334,9 @@ class TestShowFixtures: result = pytester.runpytest("--fixtures") result.stdout.fnmatch_lines( [ - "tmp_path_factory [[]session scope[]]", + "tmp_path_factory [[]session scope[]] -- *tmpdir.py*", "*for the test session*", - "tmp_path", + "tmp_path -- *", "*temporary directory*", ] ) @@ -3367,9 +3367,9 @@ class TestShowFixtures: result = pytester.runpytest("--fixtures", p) result.stdout.fnmatch_lines( """ - *tmp_path + *tmp_path -- * *fixtures defined from* - *arg1* + *arg1 -- test_show_fixtures_testmodule.py:6* *hello world* """ ) @@ -3429,10 +3429,10 @@ class TestShowFixtures: textwrap.dedent( """\ * fixtures defined from test_show_fixtures_trimmed_doc * - arg2 + arg2 -- test_show_fixtures_trimmed_doc.py:10 line1 line2 - arg1 + arg1 -- test_show_fixtures_trimmed_doc.py:3 line1 line2 """ @@ -3458,7 +3458,7 @@ class TestShowFixtures: textwrap.dedent( """\ * fixtures defined from test_show_fixtures_indented_doc * - fixture1 + fixture1 -- test_show_fixtures_indented_doc.py:3 line1 indented line """ @@ -3486,7 +3486,7 @@ class TestShowFixtures: textwrap.dedent( """\ * fixtures defined from test_show_fixtures_indented_doc_first_line_unindented * - fixture1 + fixture1 -- test_show_fixtures_indented_doc_first_line_unindented.py:3 line1 line2 indented line @@ -3514,7 +3514,7 @@ class TestShowFixtures: textwrap.dedent( """\ * fixtures defined from test_show_fixtures_indented_in_class * - fixture1 + fixture1 -- test_show_fixtures_indented_in_class.py:4 line1 line2 indented line @@ -3554,11 +3554,11 @@ class TestShowFixtures: result.stdout.fnmatch_lines( """ * fixtures defined from test_a * - fix_a + fix_a -- test_a.py:4 Fixture A * fixtures defined from test_b * - fix_b + fix_b -- test_b.py:4 Fixture B """ ) @@ -3594,11 +3594,11 @@ class TestShowFixtures: result.stdout.fnmatch_lines( """ * fixtures defined from conftest * - arg1 + arg1 -- conftest.py:3 Hello World in conftest.py * fixtures defined from test_show_fixtures_with_same_name * - arg1 + arg1 -- test_show_fixtures_with_same_name.py:3 Hi from test module """ ) diff --git a/testing/python/show_fixtures_per_test.py b/testing/python/show_fixtures_per_test.py index 2a1513273..f756dca41 100644 --- a/testing/python/show_fixtures_per_test.py +++ b/testing/python/show_fixtures_per_test.py @@ -29,7 +29,7 @@ def test_fixtures_in_module(pytester: Pytester) -> None: [ "*fixtures used by test_arg1*", "*(test_fixtures_in_module.py:9)*", - "arg1", + "arg1 -- test_fixtures_in_module.py:6", " arg1 docstring", ] ) @@ -68,17 +68,16 @@ def test_fixtures_in_conftest(pytester: Pytester) -> None: [ "*fixtures used by test_arg2*", "*(test_fixtures_in_conftest.py:2)*", - "arg2", + "arg2 -- conftest.py:6", " arg2 docstring", "*fixtures used by test_arg3*", "*(test_fixtures_in_conftest.py:4)*", - "arg1", + "arg1 -- conftest.py:3", " arg1 docstring", - "arg2", + "arg2 -- conftest.py:6", " arg2 docstring", - "arg3", + "arg3 -- conftest.py:9", " arg3", - " docstring", ] ) @@ -112,9 +111,9 @@ def test_should_show_fixtures_used_by_test(pytester: Pytester) -> None: [ "*fixtures used by test_args*", "*(test_should_show_fixtures_used_by_test.py:6)*", - "arg1", + "arg1 -- test_should_show_fixtures_used_by_test.py:3", " arg1 from testmodule", - "arg2", + "arg2 -- conftest.py:6", " arg2 from conftest", ] ) @@ -181,3 +180,75 @@ def test_doctest_items(pytester: Pytester) -> None: assert result.ret == 0 result.stdout.fnmatch_lines(["*collected 2 items*"]) + + +def test_multiline_docstring_in_module(pytester: Pytester) -> None: + p = pytester.makepyfile( + ''' + import pytest + @pytest.fixture + def arg1(): + """Docstring content that spans across multiple lines, + through second line, + and through third line. + + Docstring content that extends into a second paragraph. + + Docstring content that extends into a third paragraph. + """ + def test_arg1(arg1): + pass + ''' + ) + + result = pytester.runpytest("--fixtures-per-test", p) + assert result.ret == 0 + + result.stdout.fnmatch_lines( + [ + "*fixtures used by test_arg1*", + "*(test_multiline_docstring_in_module.py:13)*", + "arg1 -- test_multiline_docstring_in_module.py:3", + " Docstring content that spans across multiple lines,", + " through second line,", + " and through third line.", + ] + ) + + +def test_verbose_include_multiline_docstring(pytester: Pytester) -> None: + p = pytester.makepyfile( + ''' + import pytest + @pytest.fixture + def arg1(): + """Docstring content that spans across multiple lines, + through second line, + and through third line. + + Docstring content that extends into a second paragraph. + + Docstring content that extends into a third paragraph. + """ + def test_arg1(arg1): + pass + ''' + ) + + result = pytester.runpytest("--fixtures-per-test", "-v", p) + assert result.ret == 0 + + result.stdout.fnmatch_lines( + [ + "*fixtures used by test_arg1*", + "*(test_verbose_include_multiline_docstring.py:13)*", + "arg1 -- test_verbose_include_multiline_docstring.py:3", + " Docstring content that spans across multiple lines,", + " through second line,", + " and through third line.", + " ", + " Docstring content that extends into a second paragraph.", + " ", + " Docstring content that extends into a third paragraph.", + ] + )