implement funcarg factory scope marker and ScopeMismatch detection

This commit is contained in:
holger krekel 2012-07-20 14:16:46 +02:00
parent f358fe7154
commit 80db25822c
2 changed files with 143 additions and 8 deletions

View File

@ -886,6 +886,7 @@ class FuncargRequest:
self._currentarg = None
self.funcargnames = getfuncargnames(self.function)
self.parentid = pyfuncitem.parent.nodeid
self.scope = "function"
def _getfaclist(self, argname):
faclist = self._name2factory.get(argname, None)
@ -982,6 +983,9 @@ class FuncargRequest:
try:
val = cache[cachekey]
except KeyError:
__tracebackhide__ = True
check_scope(self.scope, scope)
__tracebackhide__ = False
val = setup()
cache[cachekey] = val
if teardown is not None:
@ -1007,7 +1011,6 @@ class FuncargRequest:
factorylist = self._getfaclist(argname)
funcargfactory = factorylist.pop()
node = self._pyfuncitem
oldarg = self._currentarg
mp = monkeypatch()
mp.setattr(self, '_currentarg', argname)
try:
@ -1016,11 +1019,24 @@ class FuncargRequest:
pass
else:
mp.setattr(self, 'param', param, raising=False)
try:
self._funcargs[argname] = val = funcargfactory(request=self)
return val
finally:
mp.undo()
# implemenet funcarg marker scope
marker = getattr(funcargfactory, "funcarg", None)
scope = None
if marker is not None:
scope = marker.kwargs.get("scope")
if scope is not None:
__tracebackhide__ = True
check_scope(self.scope, scope)
__tracebackhide__ = False
mp.setattr(self, "scope", scope)
val = self.cached_setup(lambda: funcargfactory(request=self),
scope=scope)
else:
val = funcargfactory(request=self)
mp.undo()
self._funcargs[argname] = val
return val
def _getscopeitem(self, scope):
if scope == "function":
@ -1039,7 +1055,7 @@ class FuncargRequest:
def addfinalizer(self, finalizer):
"""add finalizer function to be called after test function
finished execution. """
self._addfinalizer(finalizer, scope="function")
self._addfinalizer(finalizer, scope=self.scope)
def _addfinalizer(self, finalizer, scope):
colitem = self._getscopeitem(scope)
@ -1049,3 +1065,15 @@ class FuncargRequest:
def __repr__(self):
return "<FuncargRequest for %r>" %(self._pyfuncitem)
class ScopeMismatchError(Exception):
""" A funcarg factory tries to access a funcargvalue/factory
which has a lower scope (e.g. a Session one calls a function one)
"""
scopes = "session module class function".split()
def check_scope(currentscope, newscope):
__tracebackhide__ = True
i_currentscope = scopes.index(currentscope)
i_newscope = scopes.index(newscope)
if i_newscope > i_currentscope:
raise ScopeMismatchError("You tried to access a %r scoped funcarg "
"from a %r scoped one." % (newscope, currentscope))

View File

@ -58,7 +58,7 @@ class TestClass:
])
def test_setup_teardown_class_as_classmethod(self, testdir):
testdir.makepyfile("""
testdir.makepyfile(test_mod1="""
class TestClassMethod:
@classmethod
def setup_class(cls):
@ -1698,3 +1698,110 @@ class TestFuncargMarker:
reprec = testdir.inline_run()
reprec.assertoutcome(passed=4)
def test_scope_session(self, testdir):
testdir.makepyfile("""
import pytest
l = []
@pytest.mark.funcarg(scope="module")
def pytest_funcarg__arg(request):
l.append(1)
return 1
def test_1(arg):
assert arg == 1
def test_2(arg):
assert arg == 1
assert len(l) == 1
class TestClass:
def test3(self, arg):
assert arg == 1
assert len(l) == 1
""")
reprec = testdir.inline_run()
reprec.assertoutcome(passed=3)
def test_scope_module_uses_session(self, testdir):
testdir.makepyfile("""
import pytest
l = []
@pytest.mark.funcarg(scope="module")
def pytest_funcarg__arg(request):
l.append(1)
return 1
def test_1(arg):
assert arg == 1
def test_2(arg):
assert arg == 1
assert len(l) == 1
class TestClass:
def test3(self, arg):
assert arg == 1
assert len(l) == 1
""")
reprec = testdir.inline_run()
reprec.assertoutcome(passed=3)
def test_scope_module_and_finalizer(self, testdir):
testdir.makeconftest("""
import pytest
finalized = []
created = []
@pytest.mark.funcarg(scope="module")
def pytest_funcarg__arg(request):
created.append(1)
assert request.scope == "module"
request.addfinalizer(lambda: finalized.append(1))
def pytest_funcarg__created(request):
return len(created)
def pytest_funcarg__finalized(request):
return len(finalized)
""")
testdir.makepyfile(
test_mod1="""
def test_1(arg, created, finalized):
assert created == 1
assert finalized == 0
def test_2(arg, created, finalized):
assert created == 1
assert finalized == 0""",
test_mod2="""
def test_3(arg, created, finalized):
assert created == 2
assert finalized == 1""",
test_mode3="""
def test_4(arg, created, finalized):
assert created == 3
assert finalized == 2
""")
reprec = testdir.inline_run()
reprec.assertoutcome(passed=4)
@pytest.mark.parametrize("method", [
'request.getfuncargvalue("arg")',
'request.cached_setup(lambda: None, scope="function")',
], ids=["getfuncargvalue", "cached_setup"])
def test_scope_mismatch(self, testdir, method):
testdir.makeconftest("""
import pytest
finalized = []
created = []
@pytest.mark.funcarg(scope="function")
def pytest_funcarg__arg(request):
pass
""")
testdir.makepyfile(
test_mod1="""
import pytest
@pytest.mark.funcarg(scope="session")
def pytest_funcarg__arg(request):
%s
def test_1(arg):
pass
""" % method)
result = testdir.runpytest()
assert result.ret != 0
result.stdout.fnmatch_lines([
"*ScopeMismatch*You tried*function*from*session*",
])