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