From 329f56ecec5a9fcbfa160d4b467342a7c19ef2c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9E=97=E7=8E=AE?= Date: Sat, 16 Nov 2019 14:49:17 +0800 Subject: [PATCH 1/9] Fix incorrect result of getmodpath method. --- AUTHORS | 1 + changelog/6189.bugfix.rst | 1 + src/_pytest/python.py | 3 +-- 3 files changed, 3 insertions(+), 2 deletions(-) create mode 100644 changelog/6189.bugfix.rst diff --git a/AUTHORS b/AUTHORS index d0e584f63..c10ee5c15 100644 --- a/AUTHORS +++ b/AUTHORS @@ -261,6 +261,7 @@ Virgil Dupras Vitaly Lashmanov Vlad Dragos Volodymyr Piskun +Wei Lin Wil Cooley William Lee Wim Glenn diff --git a/changelog/6189.bugfix.rst b/changelog/6189.bugfix.rst new file mode 100644 index 000000000..060a2260a --- /dev/null +++ b/changelog/6189.bugfix.rst @@ -0,0 +1 @@ +Fix incorrect result of ``getmodpath`` method. diff --git a/src/_pytest/python.py b/src/_pytest/python.py index b8b365ad3..734a92f9b 100644 --- a/src/_pytest/python.py +++ b/src/_pytest/python.py @@ -285,8 +285,7 @@ class PyobjMixin(PyobjContext): break parts.append(name) parts.reverse() - s = ".".join(parts) - return s.replace(".[", "[") + return ".".join(parts) def reportinfo(self): # XXX caching? From 9c681b45e39a144f8c80abbd66eb4db0e185a238 Mon Sep 17 00:00:00 2001 From: TH3CHARLie Date: Sat, 16 Nov 2019 17:34:05 +0800 Subject: [PATCH 2/9] change: #3985 also introduce --- CHANGELOG.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index b1a988de8..47356d1d9 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1901,7 +1901,8 @@ Features live-logging is enabled and/or when they are logged to a file. -- `#3985 `_: Introduce ``tmp_path`` as a fixture providing a Path object. +- `#3985 `_: Introduce ``tmp_path`` as a fixture providing a Path object. Also introduce ``tmp_path_factory`` as + a session-scoped fixture for creating arbitrary temporary directories from any other fixture or test. - `#4013 `_: Deprecation warnings are now shown even if you customize the warnings filters yourself. In the previous version From b090ac62048990cc4d54dab841e81a8921b97284 Mon Sep 17 00:00:00 2001 From: TH3CHARLie Date: Sat, 16 Nov 2019 18:01:08 +0800 Subject: [PATCH 3/9] remove trailing-whitespace --- CHANGELOG.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 47356d1d9..e9ac09c8e 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1901,7 +1901,7 @@ Features live-logging is enabled and/or when they are logged to a file. -- `#3985 `_: Introduce ``tmp_path`` as a fixture providing a Path object. Also introduce ``tmp_path_factory`` as +- `#3985 `_: Introduce ``tmp_path`` as a fixture providing a Path object. Also introduce ``tmp_path_factory`` as a session-scoped fixture for creating arbitrary temporary directories from any other fixture or test. From 9e759010d9e9bf6ff10766c54f37bdb6ce1266c2 Mon Sep 17 00:00:00 2001 From: JoshKarpel Date: Sun, 17 Nov 2019 16:45:42 -0600 Subject: [PATCH 4/9] resolve #2049 --- src/_pytest/setupplan.py | 3 +- testing/python/setup_plan.py | 103 +++++++++++++++++++++++++++++++++++ 2 files changed, 105 insertions(+), 1 deletion(-) diff --git a/src/_pytest/setupplan.py b/src/_pytest/setupplan.py index 697746f20..6fdd3aed0 100644 --- a/src/_pytest/setupplan.py +++ b/src/_pytest/setupplan.py @@ -16,7 +16,8 @@ def pytest_addoption(parser): def pytest_fixture_setup(fixturedef, request): # Will return a dummy fixture if the setuponly option is provided. if request.config.option.setupplan: - fixturedef.cached_result = (None, None, None) + my_cache_key = fixturedef.cache_key(request) + fixturedef.cached_result = (None, my_cache_key, None) return fixturedef.cached_result diff --git a/testing/python/setup_plan.py b/testing/python/setup_plan.py index e323ba240..8ff8bfc45 100644 --- a/testing/python/setup_plan.py +++ b/testing/python/setup_plan.py @@ -17,3 +17,106 @@ def test_show_fixtures_and_test(testdir, dummy_yaml_custom_test): result.stdout.fnmatch_lines( ["*SETUP F arg*", "*test_arg (fixtures used: arg)", "*TEARDOWN F arg*"] ) + + +def test_show_multi_test_fixture_setup_and_teardown_correctly_simple(testdir): + """ + Verify that when a fixture lives for longer than a single test, --setup-plan + correctly displays the SETUP/TEARDOWN indicators the right number of times. + + As reported in https://github.com/pytest-dev/pytest/issues/2049 + --setup-plan was showing SETUP/TEARDOWN on every test, even when the fixture + should persist through multiple tests. + + (Note that this bug never affected actual test execution, which used the + correct fixture lifetimes. It was purely a display bug for --setup-plan, and + did not affect the related --setup-show or --setup-only.) + """ + testdir.makepyfile( + """ + import pytest + + @pytest.fixture(scope = 'class') + def fix(): + return object() + + class TestClass: + def test_one(self, fix): + assert False + + def test_two(self, fix): + assert False + """ + ) + + result = testdir.runpytest("--setup-plan") + assert result.ret == 0 + + setup_fragment = "SETUP C fix" + setup_count = 0 + + teardown_fragment = "TEARDOWN C fix" + teardown_count = 0 + + for line in result.stdout.lines: + if setup_fragment in line: + setup_count += 1 + if teardown_fragment in line: + teardown_count += 1 + + # before the fix this tests, there would have been a setup/teardown + # message for each test, so the counts would each have been 2 + assert setup_count == 1 + assert teardown_count == 1 + + +def test_show_multi_test_fixture_setup_and_teardown_same_as_setup_show(testdir): + """ + Verify that SETUP/TEARDOWN messages match what comes out of --setup-show. + """ + testdir.makepyfile( + """ + import pytest + + @pytest.fixture(scope = 'session') + def sess(): + return True + + @pytest.fixture(scope = 'module') + def mod(): + return True + + @pytest.fixture(scope = 'class') + def cls(): + return True + + @pytest.fixture(scope = 'function') + def func(): + return True + + + def test_outside(sess, mod, cls, func): + assert True + + + class TestCls: + def test_one(self, sess, mod, cls, func): + assert True + + def test_two(self, sess, mod, cls, func): + assert True + """ + ) + + plan_result = testdir.runpytest("--setup-plan") + show_result = testdir.runpytest("--setup-show") + + # the number and text of these lines should be identical + plan_lines = [ + l for l in plan_result.stdout.lines if "SETUP" in l or "TEARDOWN" in l + ] + show_lines = [ + l for l in show_result.stdout.lines if "SETUP" in l or "TEARDOWN" in l + ] + + assert plan_lines == show_lines From 6dfd683a0c34535c79b6baccdc60d301c64b4f76 Mon Sep 17 00:00:00 2001 From: JoshKarpel Date: Sun, 17 Nov 2019 16:47:09 -0600 Subject: [PATCH 5/9] changelog entry for #2049 --- AUTHORS | 1 + changelog/2049.bugfix.rst | 1 + 2 files changed, 2 insertions(+) create mode 100644 changelog/2049.bugfix.rst diff --git a/AUTHORS b/AUTHORS index d0e584f63..b9e6f7271 100644 --- a/AUTHORS +++ b/AUTHORS @@ -128,6 +128,7 @@ Jeff Widman Jenni Rinker John Eddie Ayson John Towler +Josh Karpel Jon Sonesen Jonas Obrist Jordan Guymon diff --git a/changelog/2049.bugfix.rst b/changelog/2049.bugfix.rst new file mode 100644 index 000000000..395396bd3 --- /dev/null +++ b/changelog/2049.bugfix.rst @@ -0,0 +1 @@ +Fix ``-setup-plan`` showing inaccurate information about fixture lifetimes. From 1e3be8ada4585ba279cfc24be8c3b09b25213804 Mon Sep 17 00:00:00 2001 From: JoshKarpel Date: Sun, 17 Nov 2019 17:14:17 -0600 Subject: [PATCH 6/9] fix whitespace issues in tests for #2049 --- testing/python/setup_plan.py | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/testing/python/setup_plan.py b/testing/python/setup_plan.py index 8ff8bfc45..a44474dd1 100644 --- a/testing/python/setup_plan.py +++ b/testing/python/setup_plan.py @@ -35,15 +35,12 @@ def test_show_multi_test_fixture_setup_and_teardown_correctly_simple(testdir): testdir.makepyfile( """ import pytest - @pytest.fixture(scope = 'class') def fix(): return object() - class TestClass: def test_one(self, fix): assert False - def test_two(self, fix): assert False """ @@ -77,32 +74,23 @@ def test_show_multi_test_fixture_setup_and_teardown_same_as_setup_show(testdir): testdir.makepyfile( """ import pytest - @pytest.fixture(scope = 'session') def sess(): return True - @pytest.fixture(scope = 'module') def mod(): return True - @pytest.fixture(scope = 'class') def cls(): return True - @pytest.fixture(scope = 'function') def func(): return True - - def test_outside(sess, mod, cls, func): assert True - - class TestCls: def test_one(self, sess, mod, cls, func): assert True - def test_two(self, sess, mod, cls, func): assert True """ From 46ffdf0e3a98bbb6ecb2393ee706ed8250f56ade Mon Sep 17 00:00:00 2001 From: Josh Karpel Date: Sun, 17 Nov 2019 17:17:47 -0600 Subject: [PATCH 7/9] Update AUTHORS --- AUTHORS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AUTHORS b/AUTHORS index b9e6f7271..1f136d83e 100644 --- a/AUTHORS +++ b/AUTHORS @@ -128,13 +128,13 @@ Jeff Widman Jenni Rinker John Eddie Ayson John Towler -Josh Karpel Jon Sonesen Jonas Obrist Jordan Guymon Jordan Moldow Jordan Speicher Joseph Hunkeler +Josh Karpel Joshua Bronson Jurko Gospodnetić Justyna Janczyszyn From 5d5f48097922dae26da06a12482a7a74de7ba924 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9E=97=E7=8E=AE?= Date: Mon, 18 Nov 2019 23:46:18 +0800 Subject: [PATCH 8/9] Hardening an existing test for demonstrating this change. --- testing/test_collection.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/testing/test_collection.py b/testing/test_collection.py index 8050e80f9..fe5d66e94 100644 --- a/testing/test_collection.py +++ b/testing/test_collection.py @@ -685,6 +685,8 @@ class Test_genitems: def test_example_items1(self, testdir): p = testdir.makepyfile( """ + import pytest + def testone(): pass @@ -693,19 +695,24 @@ class Test_genitems: pass class TestY(TestX): - pass + @pytest.mark.parametrize("arg0", [".["]) + def testmethod_two(self, arg0): + pass """ ) items, reprec = testdir.inline_genitems(p) - assert len(items) == 3 + assert len(items) == 4 assert items[0].name == "testone" assert items[1].name == "testmethod_one" assert items[2].name == "testmethod_one" + assert items[3].name == "testmethod_two[.[]" # let's also test getmodpath here assert items[0].getmodpath() == "testone" assert items[1].getmodpath() == "TestX.testmethod_one" assert items[2].getmodpath() == "TestY.testmethod_one" + # PR #6202: Fix incorrect result of getmodpath method. (Resolves issue #6189) + assert items[3].getmodpath() == "TestY.testmethod_two[.[]" s = items[0].getmodpath(stopatmodule=False) assert s.endswith("test_example_items1.testone") From 63a23d876cad98d42f03cf6c6f397513e96ffcdb Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Mon, 18 Nov 2019 16:01:44 -0800 Subject: [PATCH 9/9] Remove check for os.symlink, always there in py3+ --- testing/acceptance_test.py | 1 - 1 file changed, 1 deletion(-) diff --git a/testing/acceptance_test.py b/testing/acceptance_test.py index ad9c37737..284796a42 100644 --- a/testing/acceptance_test.py +++ b/testing/acceptance_test.py @@ -754,7 +754,6 @@ class TestInvocationVariants: result = testdir.runpytest(str(p) + "::test", "--doctest-modules") result.stdout.fnmatch_lines(["*1 passed*"]) - @pytest.mark.skipif(not hasattr(os, "symlink"), reason="requires symlinks") def test_cmdline_python_package_symlink(self, testdir, monkeypatch): """ test --pyargs option with packages with path containing symlink can