diff --git a/CHANGELOG b/CHANGELOG index faf63a346..0c7f453e5 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -5,6 +5,7 @@ Changes between 2.3.3 and 2.3.4.dev with autouse fixtures. If you need generative tests, use @pytest.mark.parametrize or pytest_generate_tests, see the many examples at http://pytest.org/latest/example/parametrize.html +- fix issue226 - LIFO ordering for fixture teardowns - fix issue224 - invocations with >256 char arguments now work - fix issue91 - add/discuss package/directory level setups in example - allow to dynamically define markers via diff --git a/_pytest/__init__.py b/_pytest/__init__.py index a61598a98..b3ea02e4e 100644 --- a/_pytest/__init__.py +++ b/_pytest/__init__.py @@ -1,2 +1,2 @@ # -__version__ = '2.3.4.dev4' +__version__ = '2.3.4.dev5' diff --git a/_pytest/python.py b/_pytest/python.py index 1a722bff4..fa3563ad4 100644 --- a/_pytest/python.py +++ b/_pytest/python.py @@ -1224,6 +1224,7 @@ class FixtureRequest(FuncargnamesCompatAttr): if paramscopenum != scopenum_subfunction: scope = scopes[paramscopenum] + # check if a higher-level scoped fixture accesses a lower level one if scope is not None: __tracebackhide__ = True if scopemismatch(self.scope, scope): @@ -1236,15 +1237,18 @@ class FixtureRequest(FuncargnamesCompatAttr): __tracebackhide__ = False mp.setattr(self, "scope", scope) + # route request.addfinalizer to fixturedef + mp.setattr(self, "addfinalizer", fixturedef.addfinalizer) + + # perform the fixture call + val = fixturedef.execute(request=self) + # prepare finalization according to scope # (XXX analyse exact finalizing mechanics / cleanup) self.session._setupstate.addfinalizer(fixturedef.finish, self.node) self._fixturemanager.addargfinalizer(fixturedef.finish, argname) for subargname in fixturedef.argnames: # XXX all deps? self._fixturemanager.addargfinalizer(fixturedef.finish, subargname) - mp.setattr(self, "addfinalizer", fixturedef.addfinalizer) - # finally perform the fixture call - val = fixturedef.execute(request=self) mp.undo() return val @@ -1503,6 +1507,8 @@ class FixtureManager: items[:] = parametrize_sorted(items, set(), {}, 0) def pytest_runtest_teardown(self, item, nextitem): + # XXX teardown needs to be normalized for parametrized and + # no-parametrized functions try: cs1 = item.callspec except AttributeError: @@ -1524,7 +1530,7 @@ class FixtureManager: keylist.sort() for (scopenum, name, param) in keylist: item.session._setupstate._callfinalizers((name, param)) - l = self._arg2finish.get(name) + l = self._arg2finish.pop(name, None) if l is not None: for fin in reversed(l): fin() diff --git a/setup.py b/setup.py index 2970ed328..626a82e55 100644 --- a/setup.py +++ b/setup.py @@ -48,7 +48,7 @@ def main(): name='pytest', description='py.test: simple powerful testing with Python', long_description = long_description, - version='2.3.4.dev4', + version='2.3.4.dev5', url='http://pytest.org', license='MIT license', platforms=['unix', 'linux', 'osx', 'cygwin', 'win32'], diff --git a/testing/python/fixture.py b/testing/python/fixture.py index a5637fbff..0e412dbe7 100644 --- a/testing/python/fixture.py +++ b/testing/python/fixture.py @@ -1105,7 +1105,7 @@ class TestAutouseManagement: reprec = testdir.inline_run() reprec.assertoutcome(passed=5) - def test_setup_funcarg_order(self, testdir): + def test_ordering_autouse_before_explicit(self, testdir): testdir.makepyfile(""" import pytest @@ -1122,6 +1122,30 @@ class TestAutouseManagement: reprec = testdir.inline_run() reprec.assertoutcome(passed=1) + @pytest.mark.issue226 + @pytest.mark.parametrize("param1", ["", "params=[1]"]) + @pytest.mark.parametrize("param2", ["", "params=[1]"]) + def test_ordering_dependencies_torndown_first(self, testdir, param1, param2): + testdir.makepyfile(""" + import pytest + l = [] + @pytest.fixture(%(param1)s) + def arg1(request): + request.addfinalizer(lambda: l.append("fin1")) + l.append("new1") + @pytest.fixture(%(param2)s) + def arg2(request, arg1): + request.addfinalizer(lambda: l.append("fin2")) + l.append("new2") + + def test_arg(arg2): + pass + def test_check(): + assert l == ["new1", "new2", "fin2", "fin1"] + """ % locals()) + reprec = testdir.inline_run("-s") + reprec.assertoutcome(passed=2) + class TestFixtureMarker: def test_parametrize(self, testdir): testdir.makepyfile("""