internally unify setup and fixture code, making setup a shortcut to fixture(autoactive=True)
This commit is contained in:
parent
9251e747af
commit
8282efbb40
|
@ -41,7 +41,7 @@ def pytest_make_collect_report(collector):
|
||||||
|
|
||||||
def call_optional(obj, name):
|
def call_optional(obj, name):
|
||||||
method = getattr(obj, name, None)
|
method = getattr(obj, name, None)
|
||||||
if method is not None and not hasattr(method, "_pytestsetup"):
|
if method is not None and not hasattr(method, "_pytestfixturefunction"):
|
||||||
# If there's any problems allow the exception to raise rather than
|
# If there's any problems allow the exception to raise rather than
|
||||||
# silently ignoring them
|
# silently ignoring them
|
||||||
method()
|
method()
|
||||||
|
|
|
@ -11,22 +11,18 @@ import _pytest
|
||||||
cutdir = py.path.local(_pytest.__file__).dirpath()
|
cutdir = py.path.local(_pytest.__file__).dirpath()
|
||||||
|
|
||||||
class FixtureFunctionMarker:
|
class FixtureFunctionMarker:
|
||||||
def __init__(self, scope, params):
|
def __init__(self, scope, params, autoactive=False):
|
||||||
self.scope = scope
|
self.scope = scope
|
||||||
self.params = params
|
self.params = params
|
||||||
|
self.autoactive = autoactive
|
||||||
|
|
||||||
def __call__(self, function):
|
def __call__(self, function):
|
||||||
function._pytestfixturefunction = self
|
function._pytestfixturefunction = self
|
||||||
return function
|
return function
|
||||||
|
|
||||||
class SetupMarker:
|
|
||||||
def __init__(self, scope):
|
|
||||||
self.scope = scope
|
|
||||||
def __call__(self, function):
|
|
||||||
function._pytestsetup = self
|
|
||||||
return function
|
|
||||||
|
|
||||||
# XXX a test fails when scope="function" how it should be, investigate
|
# XXX a test fails when scope="function" how it should be, investigate
|
||||||
def fixture(scope=None, params=None):
|
def fixture(scope=None, params=None, autoactive=False):
|
||||||
""" return a decorator to mark a fixture factory function.
|
""" return a decorator to mark a fixture factory function.
|
||||||
|
|
||||||
The name of the fixture function can be referenced in a test context
|
The name of the fixture function can be referenced in a test context
|
||||||
|
@ -42,8 +38,11 @@ def fixture(scope=None, params=None):
|
||||||
invocations of the fixture functions and their dependent
|
invocations of the fixture functions and their dependent
|
||||||
tests.
|
tests.
|
||||||
"""
|
"""
|
||||||
return FixtureFunctionMarker(scope, params)
|
return FixtureFunctionMarker(scope, params, autoactive=autoactive)
|
||||||
|
|
||||||
|
defaultfuncargprefixmarker = fixture()
|
||||||
|
|
||||||
|
# XXX remove in favour of fixture(autoactive=True)
|
||||||
def setup(scope="function"):
|
def setup(scope="function"):
|
||||||
""" return a decorator to mark a function as providing a fixture for
|
""" return a decorator to mark a function as providing a fixture for
|
||||||
a testcontext. A fixture function is executed for each scope and may
|
a testcontext. A fixture function is executed for each scope and may
|
||||||
|
@ -57,7 +56,7 @@ def setup(scope="function"):
|
||||||
of "function", "class", "module", "session".
|
of "function", "class", "module", "session".
|
||||||
Defaults to "function".
|
Defaults to "function".
|
||||||
"""
|
"""
|
||||||
return SetupMarker(scope)
|
return FixtureFunctionMarker(scope, params=None, autoactive=True)
|
||||||
|
|
||||||
def cached_property(f):
|
def cached_property(f):
|
||||||
"""returns a cached property that is calculated by function f.
|
"""returns a cached property that is calculated by function f.
|
||||||
|
@ -163,7 +162,10 @@ def pytest_pyfunc_call(__multicall__, pyfuncitem):
|
||||||
testfunction(*pyfuncitem._args)
|
testfunction(*pyfuncitem._args)
|
||||||
else:
|
else:
|
||||||
funcargs = pyfuncitem.funcargs
|
funcargs = pyfuncitem.funcargs
|
||||||
testfunction(**funcargs)
|
testargs = {}
|
||||||
|
for arg in getfuncargnames(testfunction):
|
||||||
|
testargs[arg] = funcargs[arg]
|
||||||
|
testfunction(**testargs)
|
||||||
|
|
||||||
def pytest_collect_file(path, parent):
|
def pytest_collect_file(path, parent):
|
||||||
ext = path.ext
|
ext = path.ext
|
||||||
|
@ -666,7 +668,6 @@ class Metafunc:
|
||||||
for i, valset in enumerate(argvalues):
|
for i, valset in enumerate(argvalues):
|
||||||
assert len(valset) == len(argnames)
|
assert len(valset) == len(argnames)
|
||||||
newcallspec = callspec.copy(self)
|
newcallspec = callspec.copy(self)
|
||||||
#print ("setmulti %r id %r" % (argnames, ids[i]))
|
|
||||||
newcallspec.setmulti(valtype, argnames, valset, ids[i],
|
newcallspec.setmulti(valtype, argnames, valset, ids[i],
|
||||||
scopenum)
|
scopenum)
|
||||||
newcalls.append(newcallspec)
|
newcalls.append(newcallspec)
|
||||||
|
@ -879,14 +880,19 @@ class Function(FunctionMixin, pytest.Item):
|
||||||
#req._discoverfactories()
|
#req._discoverfactories()
|
||||||
if callobj is not _dummy:
|
if callobj is not _dummy:
|
||||||
self.obj = callobj
|
self.obj = callobj
|
||||||
startindex = int(self.cls is not None)
|
self.funcargnames = self._getfixturenames()
|
||||||
self.funcargnames = getfuncargnames(self.obj, startindex=startindex)
|
|
||||||
for name, val in (py.builtin._getfuncdict(self.obj) or {}).items():
|
for name, val in (py.builtin._getfuncdict(self.obj) or {}).items():
|
||||||
setattr(self.markers, name, val)
|
setattr(self.markers, name, val)
|
||||||
if keywords:
|
if keywords:
|
||||||
for name, val in keywords.items():
|
for name, val in keywords.items():
|
||||||
setattr(self.markers, name, val)
|
setattr(self.markers, name, val)
|
||||||
|
|
||||||
|
def _getfixturenames(self):
|
||||||
|
startindex = int(self.cls is not None)
|
||||||
|
return (self.session.funcargmanager._autofixtures +
|
||||||
|
getfuncargnames(self.obj, startindex=startindex))
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def function(self):
|
def function(self):
|
||||||
"underlying python 'function' object"
|
"underlying python 'function' object"
|
||||||
|
@ -913,8 +919,8 @@ class Function(FunctionMixin, pytest.Item):
|
||||||
|
|
||||||
def setup(self):
|
def setup(self):
|
||||||
super(Function, self).setup()
|
super(Function, self).setup()
|
||||||
if hasattr(self, "_request"):
|
#if hasattr(self, "_request"):
|
||||||
self._request._callsetup()
|
# self._request._callsetup()
|
||||||
fillfuncargs(self)
|
fillfuncargs(self)
|
||||||
|
|
||||||
def __eq__(self, other):
|
def __eq__(self, other):
|
||||||
|
@ -1054,6 +1060,7 @@ class FuncargRequest:
|
||||||
"""add finalizer/teardown function to be called after the
|
"""add finalizer/teardown function to be called after the
|
||||||
last test within the requesting test context finished
|
last test within the requesting test context finished
|
||||||
execution. """
|
execution. """
|
||||||
|
# XXX usually this method is shadowed by factorydef specific ones
|
||||||
self._addfinalizer(finalizer, scope=self.scope)
|
self._addfinalizer(finalizer, scope=self.scope)
|
||||||
|
|
||||||
def _addfinalizer(self, finalizer, scope):
|
def _addfinalizer(self, finalizer, scope):
|
||||||
|
@ -1084,13 +1091,11 @@ class FuncargRequest:
|
||||||
def _fillfuncargs(self):
|
def _fillfuncargs(self):
|
||||||
item = self._pyfuncitem
|
item = self._pyfuncitem
|
||||||
funcargnames = getattr(item, "funcargnames", self.funcargnames)
|
funcargnames = getattr(item, "funcargnames", self.funcargnames)
|
||||||
|
|
||||||
for argname in funcargnames:
|
for argname in funcargnames:
|
||||||
if argname not in item.funcargs:
|
if argname not in item.funcargs:
|
||||||
item.funcargs[argname] = self.getfuncargvalue(argname)
|
item.funcargs[argname] = self.getfuncargvalue(argname)
|
||||||
|
|
||||||
def _callsetup(self):
|
|
||||||
self.funcargmanager.ensure_setupcalls(self)
|
|
||||||
|
|
||||||
def cached_setup(self, setup, teardown=None, scope="module", extrakey=None):
|
def cached_setup(self, setup, teardown=None, scope="module", extrakey=None):
|
||||||
""" (deprecated) Return a testing resource managed by ``setup`` &
|
""" (deprecated) Return a testing resource managed by ``setup`` &
|
||||||
``teardown`` calls. ``scope`` and ``extrakey`` determine when the
|
``teardown`` calls. ``scope`` and ``extrakey`` determine when the
|
||||||
|
@ -1154,20 +1159,19 @@ class FuncargRequest:
|
||||||
factorydef = factorydeflist.pop()
|
factorydef = factorydeflist.pop()
|
||||||
self._factorystack.append(factorydef)
|
self._factorystack.append(factorydef)
|
||||||
try:
|
try:
|
||||||
return self._getfuncargvalue(factorydef)
|
result = self._getfuncargvalue(factorydef)
|
||||||
|
self._funcargs[argname] = result
|
||||||
|
return result
|
||||||
finally:
|
finally:
|
||||||
self._factorystack.pop()
|
self._factorystack.pop()
|
||||||
|
|
||||||
def _getfuncargvalue(self, factorydef):
|
def _getfuncargvalue(self, factorydef):
|
||||||
# collect funcargs from the factory
|
if factorydef.active:
|
||||||
newnames = factorydef.funcargnames
|
return factorydef.cached_result
|
||||||
argname = factorydef.argname
|
|
||||||
factory_kwargs = {}
|
|
||||||
def fillfactoryargs():
|
|
||||||
for newname in newnames:
|
|
||||||
val = self.getfuncargvalue(newname)
|
|
||||||
factory_kwargs[newname] = val
|
|
||||||
|
|
||||||
|
# prepare request scope and param attributes before
|
||||||
|
# calling into factory
|
||||||
|
argname = factorydef.argname
|
||||||
node = self._pyfuncitem
|
node = self._pyfuncitem
|
||||||
mp = monkeypatch()
|
mp = monkeypatch()
|
||||||
mp.setattr(self, '_currentarg', argname)
|
mp.setattr(self, '_currentarg', argname)
|
||||||
|
@ -1177,9 +1181,7 @@ class FuncargRequest:
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
mp.setattr(self, 'param', param, raising=False)
|
mp.setattr(self, 'param', param, raising=False)
|
||||||
|
|
||||||
scope = factorydef.scope
|
scope = factorydef.scope
|
||||||
funcargfactory = factorydef.func
|
|
||||||
if scope is not None:
|
if scope is not None:
|
||||||
__tracebackhide__ = True
|
__tracebackhide__ = True
|
||||||
if scopemismatch(self.scope, scope):
|
if scopemismatch(self.scope, scope):
|
||||||
|
@ -1191,17 +1193,16 @@ class FuncargRequest:
|
||||||
(scope, argname, self.scope, "\n".join(lines))))
|
(scope, argname, self.scope, "\n".join(lines))))
|
||||||
__tracebackhide__ = False
|
__tracebackhide__ = False
|
||||||
mp.setattr(self, "scope", scope)
|
mp.setattr(self, "scope", scope)
|
||||||
kwargs = {}
|
|
||||||
if hasattr(self, "param"):
|
# prepare finalization according to scope
|
||||||
kwargs["extrakey"] = param
|
self.session._setupstate.addfinalizer(factorydef.finish, self.node)
|
||||||
fillfactoryargs()
|
self.funcargmanager.addargfinalizer(factorydef.finish, argname)
|
||||||
val = self.cached_setup(lambda: funcargfactory(**factory_kwargs),
|
for subargname in factorydef.funcargnames: # XXX all deps?
|
||||||
scope=scope, **kwargs)
|
self.funcargmanager.addargfinalizer(factorydef.finish, subargname)
|
||||||
else:
|
mp.setattr(self, "addfinalizer", factorydef.addfinalizer)
|
||||||
fillfactoryargs()
|
# finally perform the factory call
|
||||||
val = funcargfactory(**factory_kwargs)
|
val = factorydef.execute(request=self)
|
||||||
mp.undo()
|
mp.undo()
|
||||||
self._funcargs[argname] = val
|
|
||||||
return val
|
return val
|
||||||
|
|
||||||
def _factorytraceback(self):
|
def _factorytraceback(self):
|
||||||
|
@ -1291,8 +1292,8 @@ class FuncargManager:
|
||||||
self.arg2facspec = {}
|
self.arg2facspec = {}
|
||||||
self._seenplugins = set()
|
self._seenplugins = set()
|
||||||
self._holderobjseen = set()
|
self._holderobjseen = set()
|
||||||
self.setuplist = []
|
|
||||||
self._arg2finish = {}
|
self._arg2finish = {}
|
||||||
|
self._autofixtures = []
|
||||||
session.config.pluginmanager.register(self, "funcmanage")
|
session.config.pluginmanager.register(self, "funcmanage")
|
||||||
|
|
||||||
### XXX this hook should be called for historic events like pytest_configure
|
### XXX this hook should be called for historic events like pytest_configure
|
||||||
|
@ -1325,13 +1326,11 @@ class FuncargManager:
|
||||||
# so that the caller can reuse it and does not have to re-discover
|
# so that the caller can reuse it and does not have to re-discover
|
||||||
# factories again for each funcargname
|
# factories again for each funcargname
|
||||||
parentid = parentnode.nodeid
|
parentid = parentnode.nodeid
|
||||||
funcargnames = list(funcargnames)
|
funcargnames = self._autofixtures + list(funcargnames)
|
||||||
_, setupargs = self.getsetuplist(parentnode)
|
|
||||||
def merge(otherlist):
|
def merge(otherlist):
|
||||||
for arg in otherlist:
|
for arg in otherlist:
|
||||||
if arg not in funcargnames:
|
if arg not in funcargnames:
|
||||||
funcargnames.append(arg)
|
funcargnames.append(arg)
|
||||||
merge(setupargs)
|
|
||||||
arg2facdeflist = {}
|
arg2facdeflist = {}
|
||||||
lastlen = -1
|
lastlen = -1
|
||||||
while lastlen != len(funcargnames):
|
while lastlen != len(funcargnames):
|
||||||
|
@ -1365,6 +1364,9 @@ class FuncargManager:
|
||||||
cs1 = item.callspec
|
cs1 = item.callspec
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
# determine which fixtures are not needed anymore for the next test
|
||||||
|
keylist = []
|
||||||
for name in cs1.params:
|
for name in cs1.params:
|
||||||
try:
|
try:
|
||||||
if name in nextitem.callspec.params and \
|
if name in nextitem.callspec.params and \
|
||||||
|
@ -1372,8 +1374,13 @@ class FuncargManager:
|
||||||
continue
|
continue
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
pass
|
pass
|
||||||
key = (name, cs1.params[name])
|
key = (-cs1._arg2scopenum[name], name, cs1.params[name])
|
||||||
item.session._setupstate._callfinalizers(key)
|
keylist.append(key)
|
||||||
|
|
||||||
|
# sort by scope (function scope first, then higher ones)
|
||||||
|
keylist.sort()
|
||||||
|
for (scopenum, name, param) in keylist:
|
||||||
|
item.session._setupstate._callfinalizers((name, param))
|
||||||
l = self._arg2finish.get(name)
|
l = self._arg2finish.get(name)
|
||||||
if l is not None:
|
if l is not None:
|
||||||
for fin in l:
|
for fin in l:
|
||||||
|
@ -1382,55 +1389,36 @@ class FuncargManager:
|
||||||
def _parsefactories(self, holderobj, nodeid, unittest=False):
|
def _parsefactories(self, holderobj, nodeid, unittest=False):
|
||||||
if holderobj in self._holderobjseen:
|
if holderobj in self._holderobjseen:
|
||||||
return
|
return
|
||||||
#print "parsefactories", holderobj
|
|
||||||
self._holderobjseen.add(holderobj)
|
self._holderobjseen.add(holderobj)
|
||||||
for name in dir(holderobj):
|
for name in dir(holderobj):
|
||||||
#print "check", holderobj, name
|
|
||||||
obj = getattr(holderobj, name)
|
obj = getattr(holderobj, name)
|
||||||
if not callable(obj):
|
if not callable(obj):
|
||||||
continue
|
continue
|
||||||
# resource factories either have a pytest_funcarg__ prefix
|
# fixture functions have a pytest_funcarg__ prefix
|
||||||
# or are "funcarg" marked
|
# or are "@pytest.fixture" marked
|
||||||
marker = getattr(obj, "_pytestfixturefunction", None)
|
marker = getattr(obj, "_pytestfixturefunction", None)
|
||||||
if marker is not None:
|
if marker is None:
|
||||||
if not isinstance(marker, FixtureFunctionMarker):
|
if not name.startswith(self._argprefix):
|
||||||
# magic globals with __getattr__
|
|
||||||
# give us something thats wrong for that case
|
|
||||||
continue
|
continue
|
||||||
assert not name.startswith(self._argprefix)
|
marker = defaultfuncargprefixmarker
|
||||||
argname = name
|
name = name[len(self._argprefix):]
|
||||||
scope = marker.scope
|
elif not isinstance(marker, FixtureFunctionMarker):
|
||||||
params = marker.params
|
# magic globals with __getattr__ might have got us a wrong
|
||||||
elif name.startswith(self._argprefix):
|
# fixture attribute
|
||||||
argname = name[len(self._argprefix):]
|
|
||||||
scope = None
|
|
||||||
params = None
|
|
||||||
else:
|
|
||||||
# no funcargs. check if we have a setup function.
|
|
||||||
setup = getattr(obj, "_pytestsetup", None)
|
|
||||||
if setup is not None:
|
|
||||||
scope = setup.scope
|
|
||||||
sf = SetupCall(self, nodeid, obj, scope, unittest)
|
|
||||||
self.setuplist.append(sf)
|
|
||||||
continue
|
continue
|
||||||
faclist = self.arg2facspec.setdefault(argname, [])
|
else:
|
||||||
factorydef = FactoryDef(self, nodeid, argname, obj, scope, params)
|
assert not name.startswith(self._argprefix)
|
||||||
|
factorydef = FactoryDef(self, nodeid, name, obj,
|
||||||
|
marker.scope, marker.params,
|
||||||
|
unittest=unittest)
|
||||||
|
faclist = self.arg2facspec.setdefault(name, [])
|
||||||
faclist.append(factorydef)
|
faclist.append(factorydef)
|
||||||
### check scope/params mismatch?
|
if marker.autoactive:
|
||||||
|
# make sure the self._autofixtures list is always sorted
|
||||||
def getsetuplist(self, node):
|
# by scope, scopenum 0 is session
|
||||||
nodeid = node.nodeid
|
self._autofixtures.append(name)
|
||||||
l = []
|
self._autofixtures.sort(
|
||||||
allargnames = []
|
key=lambda x: self.arg2facspec[x][-1].scopenum)
|
||||||
for setupcall in self.setuplist:
|
|
||||||
if nodeid.startswith(setupcall.baseid):
|
|
||||||
l.append(setupcall)
|
|
||||||
for arg in setupcall.funcargnames:
|
|
||||||
if arg not in allargnames:
|
|
||||||
allargnames.append(arg)
|
|
||||||
l.sort(key=lambda x: x.scopenum)
|
|
||||||
return l, allargnames
|
|
||||||
|
|
||||||
|
|
||||||
def getfactorylist(self, argname, nodeid):
|
def getfactorylist(self, argname, nodeid):
|
||||||
try:
|
try:
|
||||||
|
@ -1438,20 +1426,17 @@ class FuncargManager:
|
||||||
except KeyError:
|
except KeyError:
|
||||||
return None
|
return None
|
||||||
else:
|
else:
|
||||||
return self._matchfactories(factorydeflist, nodeid)
|
return list(self._matchfactories(factorydeflist, nodeid))
|
||||||
|
|
||||||
def _matchfactories(self, factorydeflist, nodeid):
|
def _matchfactories(self, factorydeflist, nodeid):
|
||||||
l = []
|
|
||||||
for factorydef in factorydeflist:
|
for factorydef in factorydeflist:
|
||||||
#print "check", basepath, nodeid
|
|
||||||
if nodeid.startswith(factorydef.baseid):
|
if nodeid.startswith(factorydef.baseid):
|
||||||
l.append(factorydef)
|
yield factorydef
|
||||||
return l
|
|
||||||
|
|
||||||
def _raiselookupfailed(self, argname, function, nodeid, getfactb=None):
|
def _raiselookupfailed(self, argname, function, nodeid, getfactb=None):
|
||||||
available = []
|
available = []
|
||||||
for name, facdef in self.arg2facspec.items():
|
for name, facdef in self.arg2facspec.items():
|
||||||
faclist = self._matchfactories(facdef, nodeid)
|
faclist = list(self._matchfactories(facdef, nodeid))
|
||||||
if faclist:
|
if faclist:
|
||||||
available.append(name)
|
available.append(name)
|
||||||
msg = "LookupError: no factory found for argument %r" % (argname,)
|
msg = "LookupError: no factory found for argument %r" % (argname,)
|
||||||
|
@ -1460,36 +1445,6 @@ class FuncargManager:
|
||||||
lines = getfactb and getfactb() or []
|
lines = getfactb and getfactb() or []
|
||||||
raise FuncargLookupError(function, msg, lines)
|
raise FuncargLookupError(function, msg, lines)
|
||||||
|
|
||||||
def ensure_setupcalls(self, request):
|
|
||||||
setuplist, allnames = self.getsetuplist(request._pyfuncitem)
|
|
||||||
for setupcall in setuplist:
|
|
||||||
if setupcall.active:
|
|
||||||
continue
|
|
||||||
request._factorystack.append(setupcall)
|
|
||||||
mp = monkeypatch()
|
|
||||||
try:
|
|
||||||
mp.setattr(request, "scope", setupcall.scope)
|
|
||||||
kwargs = {}
|
|
||||||
for name in setupcall.funcargnames:
|
|
||||||
kwargs[name] = request.getfuncargvalue(name)
|
|
||||||
scope = setupcall.scope or "function"
|
|
||||||
scol = setupcall.scopeitem = request._getscopeitem(scope)
|
|
||||||
self.session._setupstate.addfinalizer(setupcall.finish, scol)
|
|
||||||
for argname in setupcall.funcargnames: # XXX all deps?
|
|
||||||
self.addargfinalizer(setupcall.finish, argname)
|
|
||||||
req = kwargs.get("request", None)
|
|
||||||
if req is not None:
|
|
||||||
mp.setattr(req, "addfinalizer", setupcall.addfinalizer)
|
|
||||||
# for unittest-setup methods we need to provide
|
|
||||||
# the correct instance
|
|
||||||
posargs = ()
|
|
||||||
if setupcall.unittest:
|
|
||||||
posargs = (request.instance,)
|
|
||||||
setupcall.execute(posargs, kwargs)
|
|
||||||
finally:
|
|
||||||
mp.undo()
|
|
||||||
request._factorystack.remove(setupcall)
|
|
||||||
|
|
||||||
def addargfinalizer(self, finalizer, argname):
|
def addargfinalizer(self, finalizer, argname):
|
||||||
l = self._arg2finish.setdefault(argname, [])
|
l = self._arg2finish.setdefault(argname, [])
|
||||||
l.append(finalizer)
|
l.append(finalizer)
|
||||||
|
@ -1501,28 +1456,24 @@ class FuncargManager:
|
||||||
except ValueError:
|
except ValueError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
class FactoryDef:
|
||||||
class SetupCall:
|
""" A container for a factory definition. """
|
||||||
""" a container/helper for managing calls to setup functions. """
|
def __init__(self, funcargmanager, baseid, argname, func, scope, params,
|
||||||
def __init__(self, funcargmanager, baseid, func, scope, unittest):
|
unittest=False):
|
||||||
self.funcargmanager = funcargmanager
|
self.funcargmanager = funcargmanager
|
||||||
self.baseid = baseid
|
self.baseid = baseid
|
||||||
self.func = func
|
self.func = func
|
||||||
|
self.argname = argname
|
||||||
|
self.scope = scope
|
||||||
|
self.scopenum = scopes.index(scope or "function")
|
||||||
|
self.params = params
|
||||||
startindex = unittest and 1 or None
|
startindex = unittest and 1 or None
|
||||||
self.funcargnames = getfuncargnames(func, startindex=startindex)
|
self.funcargnames = getfuncargnames(func, startindex=startindex)
|
||||||
self.scope = scope
|
self.unittest = unittest
|
||||||
self.scopenum = scopes.index(scope)
|
|
||||||
self.active = False
|
self.active = False
|
||||||
self.unittest= unittest
|
|
||||||
self._finalizer = []
|
self._finalizer = []
|
||||||
|
|
||||||
def execute(self, posargs, kwargs):
|
|
||||||
assert not self.active
|
|
||||||
self.active = True
|
|
||||||
self.func(*posargs, **kwargs)
|
|
||||||
|
|
||||||
def addfinalizer(self, finalizer):
|
def addfinalizer(self, finalizer):
|
||||||
assert self.active
|
|
||||||
self._finalizer.append(finalizer)
|
self._finalizer.append(finalizer)
|
||||||
|
|
||||||
def finish(self):
|
def finish(self):
|
||||||
|
@ -1532,17 +1483,23 @@ class SetupCall:
|
||||||
# check neccesity of next commented call
|
# check neccesity of next commented call
|
||||||
self.funcargmanager.removefinalizer(self.finish)
|
self.funcargmanager.removefinalizer(self.finish)
|
||||||
self.active = False
|
self.active = False
|
||||||
|
#print "finished", self
|
||||||
|
#del self.cached_result
|
||||||
|
|
||||||
class FactoryDef:
|
def execute(self, request):
|
||||||
""" A container for a factory definition. """
|
kwargs = {}
|
||||||
def __init__(self, funcargmanager, baseid, argname, func, scope, params):
|
for newname in self.funcargnames:
|
||||||
self.funcargmanager = funcargmanager
|
kwargs[newname] = request.getfuncargvalue(newname)
|
||||||
self.baseid = baseid
|
if self.unittest:
|
||||||
self.func = func
|
result = self.func(request.instance, **kwargs)
|
||||||
self.argname = argname
|
else:
|
||||||
self.scope = scope
|
result = self.func(**kwargs)
|
||||||
self.params = params
|
self.active = True
|
||||||
self.funcargnames = getfuncargnames(func)
|
self.cached_result = result
|
||||||
|
return result
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return "<FactoryDef name=%r scope=%r>" % (self.argname, self.scope)
|
||||||
|
|
||||||
def getfuncargnames(function, startindex=None):
|
def getfuncargnames(function, startindex=None):
|
||||||
# XXX merge with main.py's varnames
|
# XXX merge with main.py's varnames
|
||||||
|
@ -1634,5 +1591,5 @@ def getfuncargparams(item, ignore, scopenum, cache):
|
||||||
def xunitsetup(obj, name):
|
def xunitsetup(obj, name):
|
||||||
meth = getattr(obj, name, None)
|
meth = getattr(obj, name, None)
|
||||||
if meth is not None:
|
if meth is not None:
|
||||||
if not hasattr(meth, "_pytestsetup"):
|
if not hasattr(meth, "_pytestfixturefunction"):
|
||||||
return meth
|
return meth
|
||||||
|
|
|
@ -52,6 +52,9 @@ class UnitTestCase(pytest.Class):
|
||||||
class TestCaseFunction(pytest.Function):
|
class TestCaseFunction(pytest.Function):
|
||||||
_excinfo = None
|
_excinfo = None
|
||||||
|
|
||||||
|
def _getfixturenames(self):
|
||||||
|
return list(self.session.funcargmanager._autofixtures)
|
||||||
|
|
||||||
def setup(self):
|
def setup(self):
|
||||||
self._testcase = self.parent.obj(self.name)
|
self._testcase = self.parent.obj(self.name)
|
||||||
self._obj = getattr(self._testcase, self.name)
|
self._obj = getattr(self._testcase, self.name)
|
||||||
|
@ -62,7 +65,7 @@ class TestCaseFunction(pytest.Function):
|
||||||
if hasattr(self._testcase, 'setup_method'):
|
if hasattr(self._testcase, 'setup_method'):
|
||||||
self._testcase.setup_method(self._obj)
|
self._testcase.setup_method(self._obj)
|
||||||
if hasattr(self, "_request"):
|
if hasattr(self, "_request"):
|
||||||
self._request._callsetup()
|
self._request._fillfuncargs()
|
||||||
|
|
||||||
def teardown(self):
|
def teardown(self):
|
||||||
if hasattr(self._testcase, 'teardown_method'):
|
if hasattr(self._testcase, 'teardown_method'):
|
||||||
|
|
|
@ -276,8 +276,10 @@ class TestFunction:
|
||||||
assert hasattr(modcol.obj, 'test_func')
|
assert hasattr(modcol.obj, 'test_func')
|
||||||
|
|
||||||
def test_function_equality(self, testdir, tmpdir):
|
def test_function_equality(self, testdir, tmpdir):
|
||||||
|
from _pytest.python import FuncargManager
|
||||||
config = testdir.parseconfigure()
|
config = testdir.parseconfigure()
|
||||||
session = testdir.Session(config)
|
session = testdir.Session(config)
|
||||||
|
session.funcargmanager = FuncargManager(session)
|
||||||
def func1():
|
def func1():
|
||||||
pass
|
pass
|
||||||
def func2():
|
def func2():
|
||||||
|
@ -576,21 +578,18 @@ class TestFillFuncArgs:
|
||||||
assert item.funcargs['other'] == 42
|
assert item.funcargs['other'] == 42
|
||||||
|
|
||||||
def test_funcarg_lookup_modulelevel(self, testdir):
|
def test_funcarg_lookup_modulelevel(self, testdir):
|
||||||
modcol = testdir.getmodulecol("""
|
testdir.makepyfile("""
|
||||||
def pytest_funcarg__something(request):
|
def pytest_funcarg__something(request):
|
||||||
return request.function.__name__
|
return request.function.__name__
|
||||||
|
|
||||||
class TestClass:
|
class TestClass:
|
||||||
def test_method(self, something):
|
def test_method(self, something):
|
||||||
pass
|
assert something == "test_method"
|
||||||
def test_func(something):
|
def test_func(something):
|
||||||
pass
|
assert something == "test_func"
|
||||||
""")
|
""")
|
||||||
item1, item2 = testdir.genitems([modcol])
|
reprec = testdir.inline_run()
|
||||||
funcargs.fillfuncargs(item1)
|
reprec.assertoutcome(passed=2)
|
||||||
assert item1.funcargs['something'] == "test_method"
|
|
||||||
funcargs.fillfuncargs(item2)
|
|
||||||
assert item2.funcargs['something'] == "test_func"
|
|
||||||
|
|
||||||
def test_funcarg_lookup_classlevel(self, testdir):
|
def test_funcarg_lookup_classlevel(self, testdir):
|
||||||
p = testdir.makepyfile("""
|
p = testdir.makepyfile("""
|
||||||
|
@ -1881,16 +1880,9 @@ class TestSetupDiscovery:
|
||||||
def test_parsefactories_conftest(self, testdir):
|
def test_parsefactories_conftest(self, testdir):
|
||||||
testdir.makepyfile("""
|
testdir.makepyfile("""
|
||||||
def test_check_setup(item, fm):
|
def test_check_setup(item, fm):
|
||||||
setupcalls, allnames = fm.getsetuplist(item)
|
assert len(fm._autofixtures) == 2
|
||||||
assert len(setupcalls) == 2
|
assert "perfunction2" in fm._autofixtures
|
||||||
assert setupcalls[0].func.__name__ == "perfunction"
|
assert "perfunction" in fm._autofixtures
|
||||||
assert "request" in setupcalls[0].funcargnames
|
|
||||||
assert "tmpdir" in setupcalls[0].funcargnames
|
|
||||||
assert setupcalls[1].func.__name__ == "perfunction2"
|
|
||||||
assert "request" not 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 = testdir.inline_run("-s")
|
||||||
reprec.assertoutcome(passed=1)
|
reprec.assertoutcome(passed=1)
|
||||||
|
@ -2098,8 +2090,8 @@ class TestSetupManagement:
|
||||||
class TestClass:
|
class TestClass:
|
||||||
@pytest.setup(scope="class")
|
@pytest.setup(scope="class")
|
||||||
def addteardown(self, item, request):
|
def addteardown(self, item, request):
|
||||||
request.addfinalizer(lambda: l.append("teardown-%d" % item))
|
|
||||||
l.append("setup-%d" % item)
|
l.append("setup-%d" % item)
|
||||||
|
request.addfinalizer(lambda: l.append("teardown-%d" % item))
|
||||||
def test_step1(self, item):
|
def test_step1(self, item):
|
||||||
l.append("step1-%d" % item)
|
l.append("step1-%d" % item)
|
||||||
def test_step2(self, item):
|
def test_step2(self, item):
|
||||||
|
@ -2436,17 +2428,18 @@ class TestFuncargMarker:
|
||||||
l.append("test4")
|
l.append("test4")
|
||||||
def test_5():
|
def test_5():
|
||||||
assert len(l) == 12 * 3
|
assert len(l) == 12 * 3
|
||||||
import pprint
|
expected = [
|
||||||
pprint.pprint(l)
|
|
||||||
assert l == [
|
|
||||||
'create:1', 'test1', 'fin:1', 'create:2', 'test1',
|
'create:1', 'test1', 'fin:1', 'create:2', 'test1',
|
||||||
'fin:2', 'create:mod1', 'test2', 'create:1', 'test3',
|
'fin:2', 'create:mod1', 'test2', 'create:1', 'test3',
|
||||||
'fin:1', 'create:2', 'test3', 'fin:2', 'create:1',
|
'fin:1', 'create:2', 'test3', 'fin:2', 'create:1',
|
||||||
'test4', 'fin:1', 'create:2', 'test4', 'fin:mod1',
|
'test4', 'fin:1', 'create:2', 'test4', 'fin:2',
|
||||||
'fin:2', 'create:mod2', 'test2', 'create:1', 'test3',
|
'fin:mod1', 'create:mod2', 'test2', 'create:1', 'test3',
|
||||||
'fin:1', 'create:2', 'test3', 'fin:2', 'create:1',
|
'fin:1', 'create:2', 'test3', 'fin:2', 'create:1',
|
||||||
'test4', 'fin:1', 'create:2', 'test4', 'fin:mod2',
|
'test4', 'fin:1', 'create:2', 'test4', 'fin:2',
|
||||||
'fin:2']
|
'fin:mod2']
|
||||||
|
import pprint
|
||||||
|
pprint.pprint(list(zip(l, expected)))
|
||||||
|
assert l == expected
|
||||||
""")
|
""")
|
||||||
reprec = testdir.inline_run("-v")
|
reprec = testdir.inline_run("-v")
|
||||||
reprec.assertoutcome(passed=12+1)
|
reprec.assertoutcome(passed=12+1)
|
||||||
|
@ -2707,7 +2700,7 @@ def test_request_funcargnames(testdir):
|
||||||
pass
|
pass
|
||||||
def test_function(request, farg):
|
def test_function(request, farg):
|
||||||
assert set(request.funcargnames) == \
|
assert set(request.funcargnames) == \
|
||||||
set(["tmpdir", "arg1", "request", "farg"])
|
set(["tmpdir", "sarg", "arg1", "request", "farg"])
|
||||||
""")
|
""")
|
||||||
reprec = testdir.inline_run()
|
reprec = testdir.inline_run()
|
||||||
reprec.assertoutcome(passed=1)
|
reprec.assertoutcome(passed=1)
|
||||||
|
|
Loading…
Reference in New Issue