2009-05-12 01:23:57 +08:00
|
|
|
import py
|
|
|
|
|
|
|
|
def getfuncargnames(function):
|
|
|
|
argnames = py.std.inspect.getargs(function.func_code)[0]
|
|
|
|
startindex = hasattr(function, 'im_self') and 1 or 0
|
|
|
|
numdefaults = len(function.func_defaults or ())
|
|
|
|
if numdefaults:
|
|
|
|
return argnames[startindex:-numdefaults]
|
|
|
|
return argnames[startindex:]
|
|
|
|
|
|
|
|
def fillfuncargs(function):
|
|
|
|
""" fill missing funcargs. """
|
2009-05-13 05:32:19 +08:00
|
|
|
argnames = getfuncargnames(function.obj)
|
|
|
|
if argnames:
|
|
|
|
assert not function._args, "yielded functions cannot have funcargs"
|
|
|
|
for argname in argnames:
|
2009-05-12 01:23:57 +08:00
|
|
|
if argname not in function.funcargs:
|
|
|
|
request = FuncargRequest(pyfuncitem=function, argname=argname)
|
|
|
|
try:
|
|
|
|
function.funcargs[argname] = request.call_next_provider()
|
|
|
|
except request.Error:
|
|
|
|
request._raiselookupfailed()
|
|
|
|
|
2009-05-13 05:32:19 +08:00
|
|
|
|
|
|
|
_notexists = object()
|
2009-05-12 08:05:59 +08:00
|
|
|
class CallSpec:
|
2009-05-13 05:32:19 +08:00
|
|
|
def __init__(self, id, param):
|
2009-05-12 08:05:59 +08:00
|
|
|
self.id = id
|
2009-05-13 05:32:19 +08:00
|
|
|
if param is not _notexists:
|
|
|
|
self.param = param
|
2009-05-12 08:05:59 +08:00
|
|
|
|
2009-05-13 05:32:19 +08:00
|
|
|
class Metafunc:
|
2009-05-12 01:23:57 +08:00
|
|
|
def __init__(self, function, config=None, cls=None, module=None):
|
|
|
|
self.config = config
|
|
|
|
self.module = module
|
|
|
|
self.function = function
|
|
|
|
self.funcargnames = getfuncargnames(function)
|
|
|
|
self.cls = cls
|
|
|
|
self.module = module
|
2009-05-12 07:38:09 +08:00
|
|
|
self._calls = []
|
2009-05-12 08:16:02 +08:00
|
|
|
self._ids = py.builtin.set()
|
2009-05-12 01:23:57 +08:00
|
|
|
|
2009-05-13 05:32:19 +08:00
|
|
|
def addcall(self, id=None, param=_notexists):
|
|
|
|
if id is None:
|
|
|
|
id = len(self._calls)
|
|
|
|
id = str(id)
|
|
|
|
if id in self._ids:
|
|
|
|
raise ValueError("duplicate id %r" % id)
|
|
|
|
self._ids.add(id)
|
|
|
|
self._calls.append(CallSpec(id, param))
|
2009-05-12 01:23:57 +08:00
|
|
|
|
|
|
|
class FunctionCollector(py.test.collect.Collector):
|
2009-05-12 08:05:59 +08:00
|
|
|
def __init__(self, name, parent, calls):
|
2009-05-12 01:23:57 +08:00
|
|
|
super(FunctionCollector, self).__init__(name, parent)
|
2009-05-12 08:05:59 +08:00
|
|
|
self.calls = calls
|
2009-05-12 01:23:57 +08:00
|
|
|
self.obj = getattr(self.parent.obj, name)
|
|
|
|
|
|
|
|
def collect(self):
|
|
|
|
l = []
|
2009-05-12 08:05:59 +08:00
|
|
|
for call in self.calls:
|
|
|
|
function = self.parent.Function(name="%s[%s]" %(self.name, call.id),
|
2009-05-13 05:32:19 +08:00
|
|
|
parent=self, requestparam=call.param, callobj=self.obj)
|
2009-05-12 01:23:57 +08:00
|
|
|
l.append(function)
|
|
|
|
return l
|
|
|
|
|
|
|
|
class FuncargRequest:
|
|
|
|
_argprefix = "pytest_funcarg__"
|
|
|
|
|
|
|
|
class Error(LookupError):
|
|
|
|
""" error on performing funcarg request. """
|
2009-05-13 05:32:19 +08:00
|
|
|
|
2009-05-12 01:23:57 +08:00
|
|
|
def __init__(self, pyfuncitem, argname):
|
|
|
|
self._pyfuncitem = pyfuncitem
|
|
|
|
self.argname = argname
|
|
|
|
self.function = pyfuncitem.obj
|
2009-05-12 17:29:14 +08:00
|
|
|
self.module = pyfuncitem._getparent(py.test.collect.Module).obj
|
2009-05-12 01:23:57 +08:00
|
|
|
self.cls = getattr(self.function, 'im_class', None)
|
|
|
|
self.config = pyfuncitem.config
|
|
|
|
self.fspath = pyfuncitem.fspath
|
2009-05-13 05:32:19 +08:00
|
|
|
if hasattr(pyfuncitem, '_requestparam'):
|
|
|
|
self.param = pyfuncitem._requestparam
|
2009-05-12 01:23:57 +08:00
|
|
|
self._plugins = self.config.pluginmanager.getplugins()
|
2009-05-12 17:29:14 +08:00
|
|
|
self._plugins.append(self.module)
|
2009-05-12 01:23:57 +08:00
|
|
|
self._provider = self.config.pluginmanager.listattr(
|
|
|
|
plugins=self._plugins,
|
|
|
|
attrname=self._argprefix + str(argname)
|
|
|
|
)
|
|
|
|
|
|
|
|
def call_next_provider(self):
|
|
|
|
if not self._provider:
|
|
|
|
raise self.Error("no provider methods left")
|
|
|
|
next_provider = self._provider.pop()
|
|
|
|
return next_provider(request=self)
|
|
|
|
|
|
|
|
def addfinalizer(self, finalizer):
|
|
|
|
self._pyfuncitem.addfinalizer(finalizer)
|
|
|
|
|
2009-05-13 05:32:19 +08:00
|
|
|
def __repr__(self):
|
|
|
|
return "<FuncargRequest %r for %r>" %(self.argname, self._pyfuncitem)
|
|
|
|
|
2009-05-12 01:23:57 +08:00
|
|
|
def _raiselookupfailed(self):
|
|
|
|
available = []
|
|
|
|
for plugin in self._plugins:
|
|
|
|
for name in vars(plugin.__class__):
|
|
|
|
if name.startswith(self._argprefix):
|
|
|
|
name = name[len(self._argprefix):]
|
|
|
|
if name not in available:
|
|
|
|
available.append(name)
|
2009-05-12 23:02:22 +08:00
|
|
|
fspath, lineno, msg = self._pyfuncitem.reportinfo()
|
2009-05-12 01:23:57 +08:00
|
|
|
line = "%s:%s" %(fspath, lineno)
|
|
|
|
msg = "funcargument %r not found for: %s" %(self.argname, line)
|
|
|
|
msg += "\n available funcargs: %s" %(", ".join(available),)
|
|
|
|
raise LookupError(msg)
|
|
|
|
|
|
|
|
|
|
|
|
|