Merge pull request #4860 from nicoddemus/getfixturevalue-cleanup-1895
getfixturevalue does not correctly declare dependency with the calling fixture
This commit is contained in:
commit
23ea04f910
|
@ -0,0 +1,2 @@
|
||||||
|
Fix bug where fixtures requested dynamically via ``request.getfixturevalue()`` might be teardown
|
||||||
|
before the requesting fixture.
|
|
@ -585,11 +585,13 @@ class FixtureRequest(FuncargnamesCompatAttr):
|
||||||
# call the fixture function
|
# call the fixture function
|
||||||
fixturedef.execute(request=subrequest)
|
fixturedef.execute(request=subrequest)
|
||||||
finally:
|
finally:
|
||||||
# if fixture function failed it might have registered finalizers
|
self._schedule_finalizers(fixturedef, subrequest)
|
||||||
self.session._setupstate.addfinalizer(
|
|
||||||
functools.partial(fixturedef.finish, request=subrequest),
|
def _schedule_finalizers(self, fixturedef, subrequest):
|
||||||
subrequest.node,
|
# if fixture function failed it might have registered finalizers
|
||||||
)
|
self.session._setupstate.addfinalizer(
|
||||||
|
functools.partial(fixturedef.finish, request=subrequest), subrequest.node
|
||||||
|
)
|
||||||
|
|
||||||
def _check_scope(self, argname, invoking_scope, requested_scope):
|
def _check_scope(self, argname, invoking_scope, requested_scope):
|
||||||
if argname == "request":
|
if argname == "request":
|
||||||
|
@ -659,6 +661,16 @@ class SubRequest(FixtureRequest):
|
||||||
def addfinalizer(self, finalizer):
|
def addfinalizer(self, finalizer):
|
||||||
self._fixturedef.addfinalizer(finalizer)
|
self._fixturedef.addfinalizer(finalizer)
|
||||||
|
|
||||||
|
def _schedule_finalizers(self, fixturedef, subrequest):
|
||||||
|
# if the executing fixturedef was not explicitly requested in the argument list (via
|
||||||
|
# getfixturevalue inside the fixture call) then ensure this fixture def will be finished
|
||||||
|
# first
|
||||||
|
if fixturedef.argname not in self.funcargnames:
|
||||||
|
fixturedef.addfinalizer(
|
||||||
|
functools.partial(self._fixturedef.finish, request=self)
|
||||||
|
)
|
||||||
|
super(SubRequest, self)._schedule_finalizers(fixturedef, subrequest)
|
||||||
|
|
||||||
|
|
||||||
scopes = "session package module class function".split()
|
scopes = "session package module class function".split()
|
||||||
scopenum_function = scopes.index("function")
|
scopenum_function = scopes.index("function")
|
||||||
|
|
|
@ -562,6 +562,44 @@ class TestRequestBasic(object):
|
||||||
reprec = testdir.inline_run()
|
reprec = testdir.inline_run()
|
||||||
reprec.assertoutcome(passed=1)
|
reprec.assertoutcome(passed=1)
|
||||||
|
|
||||||
|
def test_getfixturevalue_teardown(self, testdir):
|
||||||
|
"""
|
||||||
|
Issue #1895
|
||||||
|
|
||||||
|
`test_inner` requests `inner` fixture, which in turn requests `resource`
|
||||||
|
using `getfixturevalue`. `test_func` then requests `resource`.
|
||||||
|
|
||||||
|
`resource` is teardown before `inner` because the fixture mechanism won't consider
|
||||||
|
`inner` dependent on `resource` when it is used via `getfixturevalue`: `test_func`
|
||||||
|
will then cause the `resource`'s finalizer to be called first because of this.
|
||||||
|
"""
|
||||||
|
testdir.makepyfile(
|
||||||
|
"""
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
@pytest.fixture(scope='session')
|
||||||
|
def resource():
|
||||||
|
r = ['value']
|
||||||
|
yield r
|
||||||
|
r.pop()
|
||||||
|
|
||||||
|
@pytest.fixture(scope='session')
|
||||||
|
def inner(request):
|
||||||
|
resource = request.getfixturevalue('resource')
|
||||||
|
assert resource == ['value']
|
||||||
|
yield
|
||||||
|
assert resource == ['value']
|
||||||
|
|
||||||
|
def test_inner(inner):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def test_func(resource):
|
||||||
|
pass
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
result = testdir.runpytest()
|
||||||
|
result.stdout.fnmatch_lines("* 2 passed in *")
|
||||||
|
|
||||||
@pytest.mark.parametrize("getfixmethod", ("getfixturevalue", "getfuncargvalue"))
|
@pytest.mark.parametrize("getfixmethod", ("getfixturevalue", "getfuncargvalue"))
|
||||||
def test_getfixturevalue(self, testdir, getfixmethod):
|
def test_getfixturevalue(self, testdir, getfixmethod):
|
||||||
item = testdir.getitem(
|
item = testdir.getitem(
|
Loading…
Reference in New Issue