diff --git a/_pytest/main.py b/_pytest/main.py index f52088cc6..7c32a6e0d 100644 --- a/_pytest/main.py +++ b/_pytest/main.py @@ -448,7 +448,7 @@ class FuncargManager: def pytest_generate_tests(self, metafunc): funcargnames = list(metafunc.funcargnames) - setuplist, allargnames = self.getsetuplist(metafunc.parentid) + _, allargnames = self.getsetuplist(metafunc.parentid) #print "setuplist, allargnames", setuplist, allargnames funcargnames.extend(allargnames) seen = set() @@ -529,7 +529,9 @@ class FuncargManager: # no funcargs. check if we have a setup function. setup = getattr(obj, "setup", None) if setup is not None and isinstance(setup, MarkInfo): - self.setuplist.append((nodeid, obj)) + scope = setup.kwargs.get("scope") + sf = SetupCall(self, nodeid, obj, scope) + self.setuplist.append(sf) continue faclist = self.arg2facspec.setdefault(argname, []) faclist.append((nodeid, obj)) @@ -537,12 +539,10 @@ class FuncargManager: def getsetuplist(self, nodeid): l = [] allargnames = set() - for baseid, setup in self.setuplist: - #print "check", baseid, setup - if nodeid.startswith(baseid): - funcargnames = getfuncargnames(setup) - l.append((setup, funcargnames)) - allargnames.update(funcargnames) + for setupcall in self.setuplist: + if nodeid.startswith(setupcall.baseid): + l.append(setupcall) + allargnames.update(setupcall.funcargnames) return l, allargnames @@ -575,6 +575,33 @@ class FuncargManager: raise FuncargLookupError(function, msg) +class SetupCall: + """ a container/helper for managing calls to setup functions. """ + def __init__(self, funcargmanager, baseid, func, scope): + self.funcargmanager = funcargmanager + self.baseid = baseid + self.func = func + self.funcargnames = getfuncargnames(func) + self.scope = scope + self.active = False + self._finalizer = [] + + def execute(self, kwargs): + #assert not self.active + self.active = True + mp = monkeypatch() + #if "request" in kwargs: + # request = kwargs["request"] + # def addfinalizer(func): + # #scopeitem = request._getscopeitem(scope) + # self._finalizer.append(func) + # mp.setattr(request, "addfinalizer", addfinalizer) + try: + self.func(**kwargs) + finally: + mp.undo() + + class NoMatch(Exception): """ raised if matching cannot locate a matching names. """ @@ -853,3 +880,8 @@ def getfuncargnames(function, startindex=None): if numdefaults: return argnames[startindex:-numdefaults] return argnames[startindex:] + +def readscope(func, markattr): + marker = getattr(func, markattr, None) + if marker is not None: + return marker.kwargs.get("scope") diff --git a/_pytest/python.py b/_pytest/python.py index fcc782377..fa7a32bcf 100644 --- a/_pytest/python.py +++ b/_pytest/python.py @@ -3,7 +3,7 @@ import py import inspect import sys import pytest -from _pytest.main import getfslineno, getfuncargnames +from _pytest.main import getfslineno, getfuncargnames, readscope from _pytest.monkeypatch import monkeypatch import _pytest @@ -1003,21 +1003,21 @@ class FuncargRequest: setuplist, allnames = self.funcargmanager.getsetuplist( self._pyfuncitem.nodeid) mp = monkeypatch() - for setupfunc, funcargnames in setuplist: + for setupcall in setuplist: kwargs = {} - for name in funcargnames: + for name in setupcall.funcargnames: if name == "request": kwargs[name] = self else: kwargs[name] = self.getfuncargvalue(name) - scope = readscope(setupfunc, "setup") - mp.setattr(self, 'scope', scope) + mp.setattr(self, 'scope', setupcall.scope) try: - if scope is None: - setupfunc(**kwargs) + if setupcall.scope is None: + setupcall.execute(kwargs) else: - self.cached_setup(lambda: setupfunc(**kwargs), scope=scope) + self.cached_setup(lambda: setupcall.execute(kwargs), + scope=setupcall.scope) finally: mp.undo() @@ -1140,7 +1140,3 @@ def slice_kwargs(names, kwargs): new_kwargs[name] = kwargs[name] return new_kwargs -def readscope(func, markattr): - marker = getattr(func, markattr, None) - if marker is not None: - return marker.kwargs.get("scope") diff --git a/testing/test_python.py b/testing/test_python.py index 13b0885cc..43e470697 100644 --- a/testing/test_python.py +++ b/testing/test_python.py @@ -1752,10 +1752,14 @@ class TestSetupDiscovery: testdir.makeconftest(""" import pytest @pytest.mark.setup - def perfunction(request): + def perfunction(request, tmpdir): + pass + + @pytest.mark.funcarg + def arg1(request, tmpdir): pass @pytest.mark.setup - def perfunction2(request): + def perfunction2(request, arg1): pass def pytest_funcarg__fm(request): @@ -1769,12 +1773,16 @@ class TestSetupDiscovery: def test_parsefactories_conftest(self, testdir): testdir.makepyfile(""" def test_check_setup(item, fm): - setuplist, allnames = fm.getsetuplist(item.nodeid) - assert len(setuplist) == 2 - assert setuplist[0][0].__name__ == "perfunction" - assert "request" in setuplist[0][1] - assert setuplist[1][0].__name__ == "perfunction2" - assert "request" in setuplist[1][1] + setupcalls, allnames = fm.getsetuplist(item.nodeid) + assert len(setupcalls) == 2 + assert setupcalls[0].func.__name__ == "perfunction" + assert "request" in setupcalls[0].funcargnames + assert "tmpdir" in setupcalls[0].funcargnames + assert setupcalls[1].func.__name__ == "perfunction2" + assert "request" in setupcalls[1].funcargnames + assert "arg1" in setupcalls[1].funcargnames + assert "tmpdir" not in setupcalls[1].funcargnames + #assert "tmpdir" in setupcalls[1].depfuncargs """) reprec = testdir.inline_run("-s") reprec.assertoutcome(passed=1)