Cache exception raised in fixtures according to their scope
Without this if a session scoped fixture fails it's setup it will be re-tried each time it is requested. Especially in case of skip or failure exceptions this can be undesirable, but caching makes sense for all exceptions.
This commit is contained in:
parent
65a145e2a7
commit
c46e2cbbc7
|
@ -1,6 +1,8 @@
|
|||
NEXT (2.6)
|
||||
-----------------------------------
|
||||
|
||||
- Cache exceptions from fixtures according to their scope (issue 467).
|
||||
|
||||
- fix issue514: teach assertion reinterpretation about private class attributes
|
||||
|
||||
- change -v output to include full node IDs of tests. Users can copy
|
||||
|
@ -59,10 +61,6 @@ NEXT (2.6)
|
|||
|
||||
- fix issue483: trial/py33 works now properly. Thanks Daniel Grana for PR.
|
||||
|
||||
- improve example for pytest integration with "python setup.py test"
|
||||
which now has a generic "-a" or "--pytest-args" option where you
|
||||
can pass additional options as a quoted string. Thanks Trevor Bekolay.
|
||||
|
||||
- simplified internal capturing mechanism and made it more robust
|
||||
against tests or setups changing FD1/FD2, also better integrated
|
||||
now with pytest.pdb() in single tests.
|
||||
|
@ -89,9 +87,6 @@ NEXT (2.6)
|
|||
functions, including unittest-style Classes. If set to False, the
|
||||
test will not be collected.
|
||||
|
||||
- fix issue512: show "<notset>" for arguments which might not be set
|
||||
in monkeypatch plugin. Improves output in documentation.
|
||||
|
||||
|
||||
2.5.2
|
||||
-----------------------------------
|
||||
|
|
|
@ -1337,7 +1337,7 @@ class FixtureRequest(FuncargnamesCompatAttr):
|
|||
except FixtureLookupError:
|
||||
if argname == "request":
|
||||
class PseudoFixtureDef:
|
||||
cached_result = (self, [0])
|
||||
cached_result = (self, [0], None)
|
||||
return PseudoFixtureDef
|
||||
raise
|
||||
result = self._getfuncargvalue(fixturedef)
|
||||
|
@ -1810,7 +1810,7 @@ class FixtureDef:
|
|||
kwargs = {}
|
||||
for argname in self.argnames:
|
||||
fixturedef = request._get_active_fixturedef(argname)
|
||||
result, arg_cache_key = fixturedef.cached_result
|
||||
result, arg_cache_key, exc = fixturedef.cached_result
|
||||
kwargs[argname] = result
|
||||
if argname != "request":
|
||||
fixturedef.addfinalizer(self.finish)
|
||||
|
@ -1818,13 +1818,12 @@ class FixtureDef:
|
|||
my_cache_key = request.param_index
|
||||
cached_result = getattr(self, "cached_result", None)
|
||||
if cached_result is not None:
|
||||
#print argname, "Found cached_result", cached_result
|
||||
#print argname, "param_index", param_index
|
||||
result, cache_key = cached_result
|
||||
result, cache_key, err = cached_result
|
||||
if my_cache_key == cache_key:
|
||||
#print request.fixturename, "CACHE HIT", repr(my_cache_key)
|
||||
return result
|
||||
#print request.fixturename, "CACHE MISS"
|
||||
if err is not None:
|
||||
py.builtin._reraise(*err)
|
||||
else:
|
||||
return result
|
||||
# we have a previous but differently parametrized fixture instance
|
||||
# so we need to tear it down before creating a new one
|
||||
self.finish()
|
||||
|
@ -1841,9 +1840,13 @@ class FixtureDef:
|
|||
fixturefunc = getimfunc(self.func)
|
||||
if fixturefunc != self.func:
|
||||
fixturefunc = fixturefunc.__get__(request.instance)
|
||||
result = call_fixture_func(fixturefunc, request, kwargs,
|
||||
self.yieldctx)
|
||||
self.cached_result = (result, my_cache_key)
|
||||
try:
|
||||
result = call_fixture_func(fixturefunc, request, kwargs,
|
||||
self.yieldctx)
|
||||
except Exception:
|
||||
self.cached_result = (None, my_cache_key, sys.exc_info())
|
||||
raise
|
||||
self.cached_result = (result, my_cache_key, None)
|
||||
return result
|
||||
|
||||
def __repr__(self):
|
||||
|
|
|
@ -1430,6 +1430,25 @@ class TestFixtureMarker:
|
|||
reprec = testdir.inline_run()
|
||||
reprec.assertoutcome(passed=3)
|
||||
|
||||
def test_scope_session_exc(self, testdir):
|
||||
testdir.makepyfile("""
|
||||
import pytest
|
||||
l = []
|
||||
@pytest.fixture(scope="session")
|
||||
def fix():
|
||||
l.append(1)
|
||||
pytest.skip('skipping')
|
||||
|
||||
def test_1(fix):
|
||||
pass
|
||||
def test_2(fix):
|
||||
pass
|
||||
def test_last():
|
||||
assert l == [1]
|
||||
""")
|
||||
reprec = testdir.inline_run()
|
||||
reprec.assertoutcome(skipped=2, passed=1)
|
||||
|
||||
def test_scope_module_uses_session(self, testdir):
|
||||
testdir.makepyfile("""
|
||||
import pytest
|
||||
|
|
Loading…
Reference in New Issue