introduce a funcargcall object, holding meta information
This commit is contained in:
parent
b57fb9fd47
commit
9dc79fd187
|
@ -454,24 +454,18 @@ class FuncargManager:
|
|||
seen = set()
|
||||
while funcargnames:
|
||||
argname = funcargnames.pop(0)
|
||||
if argname in seen:
|
||||
if argname in seen or argname == "request":
|
||||
continue
|
||||
seen.add(argname)
|
||||
faclist = self.getfactorylist(argname, metafunc.parentid,
|
||||
metafunc.function, raising=False)
|
||||
if faclist is None:
|
||||
continue # will raise FuncargLookupError at setup time
|
||||
for fac in faclist:
|
||||
marker = getattr(fac, "funcarg", None)
|
||||
if marker is not None:
|
||||
params = marker.kwargs.get("params")
|
||||
scope = marker.kwargs.get("scope", "function")
|
||||
if params is not None:
|
||||
metafunc.parametrize(argname, params, indirect=True,
|
||||
scope=scope)
|
||||
newfuncargnames = getfuncargnames(fac)
|
||||
newfuncargnames.remove("request")
|
||||
funcargnames.extend(newfuncargnames)
|
||||
for facdef in faclist:
|
||||
if facdef.params is not None:
|
||||
metafunc.parametrize(argname, facdef.params, indirect=True,
|
||||
scope=facdef.scope)
|
||||
funcargnames.extend(facdef.funcargnames)
|
||||
|
||||
def pytest_collection_modifyitems(self, items):
|
||||
# separate parametrized setups
|
||||
|
@ -520,11 +514,18 @@ class FuncargManager:
|
|||
continue
|
||||
# funcarg factories either have a pytest_funcarg__ prefix
|
||||
# or are "funcarg" marked
|
||||
if hasattr(obj, "funcarg"):
|
||||
if not callable(obj):
|
||||
continue
|
||||
marker = getattr(obj, "funcarg", None)
|
||||
if marker is not None and isinstance(marker, MarkInfo):
|
||||
assert not name.startswith(self._argprefix)
|
||||
argname = name
|
||||
scope = marker.kwargs.get("scope")
|
||||
params = marker.kwargs.get("params")
|
||||
elif name.startswith(self._argprefix):
|
||||
argname = name[len(self._argprefix):]
|
||||
scope = None
|
||||
params = None
|
||||
else:
|
||||
# no funcargs. check if we have a setup function.
|
||||
setup = getattr(obj, "setup", None)
|
||||
|
@ -534,7 +535,9 @@ class FuncargManager:
|
|||
self.setuplist.append(sf)
|
||||
continue
|
||||
faclist = self.arg2facspec.setdefault(argname, [])
|
||||
faclist.append((nodeid, obj))
|
||||
factorydef = FactoryDef(self, nodeid, argname, obj, scope, params)
|
||||
faclist.append(factorydef)
|
||||
### check scope/params mismatch?
|
||||
|
||||
def getsetuplist(self, nodeid):
|
||||
l = []
|
||||
|
@ -548,19 +551,19 @@ class FuncargManager:
|
|||
|
||||
def getfactorylist(self, argname, nodeid, function, raising=True):
|
||||
try:
|
||||
factorydef = self.arg2facspec[argname]
|
||||
factorydeflist = self.arg2facspec[argname]
|
||||
except KeyError:
|
||||
if raising:
|
||||
self._raiselookupfailed(argname, function, nodeid)
|
||||
else:
|
||||
return self._matchfactories(factorydef, nodeid)
|
||||
return self._matchfactories(factorydeflist, nodeid)
|
||||
|
||||
def _matchfactories(self, factorydef, nodeid):
|
||||
def _matchfactories(self, factorydeflist, nodeid):
|
||||
l = []
|
||||
for baseid, factory in factorydef:
|
||||
for factorydef in factorydeflist:
|
||||
#print "check", basepath, nodeid
|
||||
if nodeid.startswith(baseid):
|
||||
l.append(factory)
|
||||
if nodeid.startswith(factorydef.baseid):
|
||||
l.append(factorydef)
|
||||
return l
|
||||
|
||||
def _raiselookupfailed(self, argname, function, nodeid):
|
||||
|
@ -575,6 +578,17 @@ class FuncargManager:
|
|||
raise FuncargLookupError(function, msg)
|
||||
|
||||
|
||||
class FactoryDef:
|
||||
""" A container for a factory definition. """
|
||||
def __init__(self, funcargmanager, baseid, argname, func, scope, params):
|
||||
self.funcargmanager = funcargmanager
|
||||
self.baseid = baseid
|
||||
self.func = func
|
||||
self.argname = argname
|
||||
self.scope = scope
|
||||
self.params = params
|
||||
self.funcargnames = getfuncargnames(func)
|
||||
|
||||
class SetupCall:
|
||||
""" a container/helper for managing calls to setup functions. """
|
||||
def __init__(self, funcargmanager, baseid, func, scope):
|
||||
|
|
|
@ -586,6 +586,8 @@ class Metafunc:
|
|||
if not isinstance(argnames, (tuple, list)):
|
||||
argnames = (argnames,)
|
||||
argvalues = [(val,) for val in argvalues]
|
||||
if scope is None:
|
||||
scope = "function"
|
||||
scopenum = scopes.index(scope)
|
||||
if not indirect:
|
||||
#XXX should we also check for the opposite case?
|
||||
|
@ -888,16 +890,15 @@ class FuncargRequest:
|
|||
self._factorystack = []
|
||||
|
||||
def _getfaclist(self, argname):
|
||||
faclist = self._name2factory.get(argname, None)
|
||||
if faclist is None:
|
||||
faclist = self.funcargmanager.getfactorylist(argname,
|
||||
self.parentid,
|
||||
self.function)
|
||||
self._name2factory[argname] = faclist
|
||||
elif not faclist:
|
||||
facdeflist = self._name2factory.get(argname, None)
|
||||
if facdeflist is None:
|
||||
facdeflist = self.funcargmanager.getfactorylist(
|
||||
argname, self.parentid, self.function)
|
||||
self._name2factory[argname] = facdeflist
|
||||
elif not facdeflist:
|
||||
self.funcargmanager._raiselookupfailed(argname, self.function,
|
||||
self.parentid)
|
||||
return faclist
|
||||
return facdeflist
|
||||
|
||||
def raiseerror(self, msg):
|
||||
""" raise a FuncargLookupError with the given message. """
|
||||
|
@ -1033,18 +1034,19 @@ class FuncargRequest:
|
|||
return self._funcargs[argname]
|
||||
except KeyError:
|
||||
pass
|
||||
factorylist = self._getfaclist(argname)
|
||||
funcargfactory = factorylist.pop()
|
||||
self._factorystack.append(funcargfactory)
|
||||
factorydeflist = self._getfaclist(argname)
|
||||
factorydef = factorydeflist.pop()
|
||||
self._factorystack.append(factorydef)
|
||||
try:
|
||||
return self._getfuncargvalue(funcargfactory, argname)
|
||||
return self._getfuncargvalue(factorydef)
|
||||
finally:
|
||||
self._factorystack.pop()
|
||||
|
||||
def _getfuncargvalue(self, funcargfactory, argname):
|
||||
def _getfuncargvalue(self, factorydef):
|
||||
# collect funcargs from the factory
|
||||
newnames = getfuncargnames(funcargfactory)
|
||||
newnames = list(factorydef.funcargnames)
|
||||
newnames.remove("request")
|
||||
argname = factorydef.argname
|
||||
factory_kwargs = {"request": self}
|
||||
def fillfactoryargs():
|
||||
for newname in newnames:
|
||||
|
@ -1060,15 +1062,15 @@ class FuncargRequest:
|
|||
else:
|
||||
mp.setattr(self, 'param', param, raising=False)
|
||||
|
||||
# implement funcarg marker scope
|
||||
scope = readscope(funcargfactory, "funcarg")
|
||||
|
||||
scope = factorydef.scope
|
||||
funcargfactory = factorydef.func
|
||||
if scope is not None:
|
||||
__tracebackhide__ = True
|
||||
if scopemismatch(self.scope, scope):
|
||||
# try to report something helpful
|
||||
lines = []
|
||||
for factory in self._factorystack:
|
||||
for factorydef in self._factorystack:
|
||||
factory = factorydef.func
|
||||
fs, lineno = getfslineno(factory)
|
||||
p = self._pyfuncitem.session.fspath.bestrelpath(fs)
|
||||
args = inspect.formatargspec(*inspect.getargspec(factory))
|
||||
|
|
|
@ -1723,7 +1723,7 @@ class TestFuncargManager:
|
|||
faclist = fm.getfactorylist(name, item.nodeid, item.obj)
|
||||
assert len(faclist) == 1
|
||||
fac = faclist[0]
|
||||
assert fac.__name__ == "pytest_funcarg__" + name
|
||||
assert fac.func.__name__ == "pytest_funcarg__" + name
|
||||
""")
|
||||
reprec = testdir.inline_run("-s")
|
||||
reprec.assertoutcome(passed=1)
|
||||
|
@ -1739,9 +1739,9 @@ class TestFuncargManager:
|
|||
faclist = fm.getfactorylist("hello", item.nodeid, item.obj)
|
||||
print faclist
|
||||
assert len(faclist) == 3
|
||||
assert faclist[0](item._request) == "conftest"
|
||||
assert faclist[1](item._request) == "module"
|
||||
assert faclist[2](item._request) == "class"
|
||||
assert faclist[0].func(item._request) == "conftest"
|
||||
assert faclist[1].func(item._request) == "module"
|
||||
assert faclist[2].func(item._request) == "class"
|
||||
""")
|
||||
reprec = testdir.inline_run("-s")
|
||||
reprec.assertoutcome(passed=1)
|
||||
|
|
Loading…
Reference in New Issue