From e31f40c2d0d827cbbf7690d47128d41ee85d5962 Mon Sep 17 00:00:00 2001 From: holger krekel Date: Thu, 21 Nov 2013 14:16:44 +0100 Subject: [PATCH] fix ordering of finalizers of parametrized interdependent fixtures. This fixes issue246 as reported. Thanks Ralph Schmitt for the precise failure example. --- CHANGELOG | 4 ++++ _pytest/python.py | 4 ++++ testing/python/fixture.py | 19 ++++++++----------- 3 files changed, 16 insertions(+), 11 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 452595f3e..54aa46a21 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -15,6 +15,10 @@ Unreleased since the unittest compat enhancements allow trial to handle it on its own +- fix ordering of finalizers of parametrized interdependent fixtures. + This fixes issue246 as reported. Thanks Ralph Schmitt for the + precise failure example. + - don't hide an ImportError when importing a plugin produces one. fixes issue375. diff --git a/_pytest/python.py b/_pytest/python.py index fda931c4a..a319e3ea8 100644 --- a/_pytest/python.py +++ b/_pytest/python.py @@ -1380,6 +1380,7 @@ class ScopeMismatchError(Exception): scopes = "session module class function subfunction".split() scopenum_subfunction = scopes.index("subfunction") +scopenum_function = scopes.index("function") def scopemismatch(currentscope, newscope): return scopes.index(newscope) > scopes.index(currentscope) @@ -1597,6 +1598,7 @@ class FixtureManager: # separate parametrized setups items[:] = parametrize_sorted(items, set(), {}, 0) + @pytest.mark.trylast def pytest_runtest_teardown(self, item, nextitem): # XXX teardown needs to be normalized for parametrized and # no-parametrized functions @@ -1620,6 +1622,8 @@ class FixtureManager: # sort by scope (function scope first, then higher ones) keylist.sort() for (scopenum, name, param) in keylist: + #if -scopenum >= scopenum_function: + # continue # handled by runner.pytest_runtest_teardown item.session._setupstate._callfinalizers((name, param)) l = self._arg2finish.pop(name, None) if l is not None: diff --git a/testing/python/fixture.py b/testing/python/fixture.py index baabc341e..e1c91e068 100644 --- a/testing/python/fixture.py +++ b/testing/python/fixture.py @@ -1810,25 +1810,23 @@ class TestFixtureMarker: testdir.makepyfile(""" import pytest + l = [] @pytest.fixture(scope="module", params=[1, 2]) def arg(request): - request.config.l = l # to access from outer x = request.param request.addfinalizer(lambda: l.append("fin%s" % x)) return request.param - - l = [] def test_1(arg): l.append(arg) def test_2(arg): l.append(arg) """) - reprec = testdir.inline_run("-v") + reprec = testdir.inline_run("-vs") reprec.assertoutcome(passed=4) - l = reprec.getcalls("pytest_configure")[0].config.l + l = reprec.getcalls("pytest_runtest_call")[0].item.module.l import pprint pprint.pprint(l) - assert len(l) == 6 + #assert len(l) == 6 assert l[0] == l[1] == 1 assert l[2] == "fin1" assert l[3] == l[4] == 2 @@ -1858,8 +1856,7 @@ class TestFixtureMarker: @pytest.mark.issue246 - @pytest.mark.xfail(reason="per-arg finalization does not respect order") - @pytest.mark.parametrize("scope", ["function", "module"]) + @pytest.mark.parametrize("scope", ["session", "function", "module"]) def test_finalizer_order_on_parametrization(self, scope, testdir): testdir.makepyfile(""" import pytest @@ -1883,11 +1880,11 @@ class TestFixtureMarker: def test_baz(base, fix2): pass + def test_other(): + pass """ % {"scope": scope}) reprec = testdir.inline_run() - reprec.assertoutcome(passed=1) - l = reprec.getcall("pytest_runtest_call").item.module.l - assert l == ["test", "fin_fix2", "fin_fix3"] + reprec.assertoutcome(passed=2) def test_parametrize_setup_function(self, testdir): testdir.makepyfile("""