implement funcarg factory scope marker and ScopeMismatch detection
This commit is contained in:
parent
f358fe7154
commit
80db25822c
|
@ -886,6 +886,7 @@ class FuncargRequest:
|
||||||
self._currentarg = None
|
self._currentarg = None
|
||||||
self.funcargnames = getfuncargnames(self.function)
|
self.funcargnames = getfuncargnames(self.function)
|
||||||
self.parentid = pyfuncitem.parent.nodeid
|
self.parentid = pyfuncitem.parent.nodeid
|
||||||
|
self.scope = "function"
|
||||||
|
|
||||||
def _getfaclist(self, argname):
|
def _getfaclist(self, argname):
|
||||||
faclist = self._name2factory.get(argname, None)
|
faclist = self._name2factory.get(argname, None)
|
||||||
|
@ -982,6 +983,9 @@ class FuncargRequest:
|
||||||
try:
|
try:
|
||||||
val = cache[cachekey]
|
val = cache[cachekey]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
|
__tracebackhide__ = True
|
||||||
|
check_scope(self.scope, scope)
|
||||||
|
__tracebackhide__ = False
|
||||||
val = setup()
|
val = setup()
|
||||||
cache[cachekey] = val
|
cache[cachekey] = val
|
||||||
if teardown is not None:
|
if teardown is not None:
|
||||||
|
@ -1007,7 +1011,6 @@ class FuncargRequest:
|
||||||
factorylist = self._getfaclist(argname)
|
factorylist = self._getfaclist(argname)
|
||||||
funcargfactory = factorylist.pop()
|
funcargfactory = factorylist.pop()
|
||||||
node = self._pyfuncitem
|
node = self._pyfuncitem
|
||||||
oldarg = self._currentarg
|
|
||||||
mp = monkeypatch()
|
mp = monkeypatch()
|
||||||
mp.setattr(self, '_currentarg', argname)
|
mp.setattr(self, '_currentarg', argname)
|
||||||
try:
|
try:
|
||||||
|
@ -1016,11 +1019,24 @@ class FuncargRequest:
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
mp.setattr(self, 'param', param, raising=False)
|
mp.setattr(self, 'param', param, raising=False)
|
||||||
try:
|
|
||||||
self._funcargs[argname] = val = funcargfactory(request=self)
|
# implemenet funcarg marker scope
|
||||||
return val
|
marker = getattr(funcargfactory, "funcarg", None)
|
||||||
finally:
|
scope = None
|
||||||
mp.undo()
|
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):
|
def _getscopeitem(self, scope):
|
||||||
if scope == "function":
|
if scope == "function":
|
||||||
|
@ -1039,7 +1055,7 @@ class FuncargRequest:
|
||||||
def addfinalizer(self, finalizer):
|
def addfinalizer(self, finalizer):
|
||||||
"""add finalizer function to be called after test function
|
"""add finalizer function to be called after test function
|
||||||
finished execution. """
|
finished execution. """
|
||||||
self._addfinalizer(finalizer, scope="function")
|
self._addfinalizer(finalizer, scope=self.scope)
|
||||||
|
|
||||||
def _addfinalizer(self, finalizer, scope):
|
def _addfinalizer(self, finalizer, scope):
|
||||||
colitem = self._getscopeitem(scope)
|
colitem = self._getscopeitem(scope)
|
||||||
|
@ -1049,3 +1065,15 @@ class FuncargRequest:
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "<FuncargRequest for %r>" %(self._pyfuncitem)
|
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))
|
||||||
|
|
|
@ -58,7 +58,7 @@ class TestClass:
|
||||||
])
|
])
|
||||||
|
|
||||||
def test_setup_teardown_class_as_classmethod(self, testdir):
|
def test_setup_teardown_class_as_classmethod(self, testdir):
|
||||||
testdir.makepyfile("""
|
testdir.makepyfile(test_mod1="""
|
||||||
class TestClassMethod:
|
class TestClassMethod:
|
||||||
@classmethod
|
@classmethod
|
||||||
def setup_class(cls):
|
def setup_class(cls):
|
||||||
|
@ -1698,3 +1698,110 @@ class TestFuncargMarker:
|
||||||
reprec = testdir.inline_run()
|
reprec = testdir.inline_run()
|
||||||
reprec.assertoutcome(passed=4)
|
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*",
|
||||||
|
])
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue