* create funcarg Request object only once per function run setup
* add getfuncargvalue() for retrieving arbitrary funcargs from a provider --HG-- branch : trunk
This commit is contained in:
parent
d1f24aa251
commit
dcee9bdd6e
|
@ -108,8 +108,6 @@ encapsulate a request for a function argument for a
|
|||
specific test function. Request objects allow providers
|
||||
to access test configuration and test context:
|
||||
|
||||
``request.argname``: name of the requested function argument
|
||||
|
||||
``request.function``: python function object requesting the argument
|
||||
|
||||
``request.cls``: class object where the test function is defined in or None.
|
||||
|
@ -120,6 +118,7 @@ to access test configuration and test context:
|
|||
|
||||
``request.param``: if exists was passed by a `parametrizing test generator`_
|
||||
|
||||
|
||||
perform scoped setup and teardown
|
||||
---------------------------------------------
|
||||
|
||||
|
@ -171,6 +170,21 @@ object that is to be closed when the test function finishes.
|
|||
request.addfinalizer(lambda: myfile.close())
|
||||
return myfile
|
||||
|
||||
requesting values of other funcargs
|
||||
---------------------------------------------
|
||||
|
||||
While setting up one function argument you may
|
||||
want to retrieve another function argument.
|
||||
|
||||
.. sourcecode:: python
|
||||
|
||||
def getfuncargvalue(name):
|
||||
""" Lookup and call function argument provider for the given name.
|
||||
Each function argument is only requested once per function setup.
|
||||
"""
|
||||
|
||||
Note that it does not matter if the test function
|
||||
specifies the requested function argument.
|
||||
|
||||
decorating other funcarg providers
|
||||
++++++++++++++++++++++++++++++++++++++++
|
||||
|
|
|
@ -10,16 +10,8 @@ def getfuncargnames(function):
|
|||
|
||||
def fillfuncargs(function):
|
||||
""" fill missing funcargs. """
|
||||
argnames = getfuncargnames(function.obj)
|
||||
if argnames:
|
||||
assert not function._args, "yielded functions cannot have funcargs"
|
||||
for argname in argnames:
|
||||
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()
|
||||
request = FuncargRequest(pyfuncitem=function)
|
||||
request._fillfuncargs()
|
||||
|
||||
|
||||
_notexists = object()
|
||||
|
@ -78,13 +70,13 @@ class FunctionCollector(py.test.collect.Collector):
|
|||
|
||||
class FuncargRequest:
|
||||
_argprefix = "pytest_funcarg__"
|
||||
_argname = None
|
||||
|
||||
class Error(LookupError):
|
||||
""" error on performing funcarg request. """
|
||||
|
||||
def __init__(self, pyfuncitem, argname):
|
||||
def __init__(self, pyfuncitem):
|
||||
self._pyfuncitem = pyfuncitem
|
||||
self.argname = argname
|
||||
self.function = pyfuncitem.obj
|
||||
self.module = pyfuncitem.getparent(py.test.collect.Module).obj
|
||||
self.cls = getattr(self.function, 'im_class', None)
|
||||
|
@ -97,14 +89,20 @@ class FuncargRequest:
|
|||
self._plugins.append(self.module)
|
||||
if self.instance is not None:
|
||||
self._plugins.append(self.instance)
|
||||
self._provider = self.config.pluginmanager.listattr(
|
||||
plugins=self._plugins,
|
||||
attrname=self._argprefix + str(argname)
|
||||
)
|
||||
self._funcargs = self._pyfuncitem.funcargs.copy()
|
||||
self._provider = {}
|
||||
|
||||
def _fillfuncargs(self):
|
||||
argnames = getfuncargnames(self.function)
|
||||
if argnames:
|
||||
assert not self._pyfuncitem._args, "yielded functions cannot have funcargs"
|
||||
for argname in argnames:
|
||||
if argname not in self._pyfuncitem.funcargs:
|
||||
self._pyfuncitem.funcargs[argname] = self.getfuncargvalue(argname)
|
||||
|
||||
def cached_setup(self, setup, teardown=None, scope="module", extrakey=None):
|
||||
if not hasattr(self.config, '_setupcache'):
|
||||
self.config._setupcache = {}
|
||||
self.config._setupcache = {} # XXX weakref?
|
||||
cachekey = (self._getscopeitem(scope), extrakey)
|
||||
cache = self.config._setupcache
|
||||
try:
|
||||
|
@ -117,11 +115,34 @@ class FuncargRequest:
|
|||
return val
|
||||
|
||||
def call_next_provider(self):
|
||||
if not self._provider:
|
||||
raise self.Error("no provider methods left")
|
||||
next_provider = self._provider.pop()
|
||||
if not self._provider[self._argname]:
|
||||
raise self.Error("no provider methods left for %r" % self._argname)
|
||||
next_provider = self._provider[self._argname].pop()
|
||||
return next_provider(request=self)
|
||||
|
||||
def getfuncargvalue(self, argname):
|
||||
try:
|
||||
return self._funcargs[argname]
|
||||
except KeyError:
|
||||
pass
|
||||
assert argname not in self._provider
|
||||
self._provider[argname] = self.config.pluginmanager.listattr(
|
||||
plugins=self._plugins,
|
||||
attrname=self._argprefix + str(argname)
|
||||
)
|
||||
# during call_next_provider() we keep state about the current
|
||||
# argument on the request object - we may go for instantiating
|
||||
# request objects per each funcargname if neccessary
|
||||
oldname = self._argname
|
||||
self._argname = argname
|
||||
try:
|
||||
self._funcargs[argname] = res = self.call_next_provider()
|
||||
except self.Error:
|
||||
self._raiselookupfailed(argname)
|
||||
if oldname:
|
||||
self._argname = oldname
|
||||
return res
|
||||
|
||||
def _getscopeitem(self, scope):
|
||||
if scope == "function":
|
||||
return self._pyfuncitem
|
||||
|
@ -134,9 +155,9 @@ class FuncargRequest:
|
|||
self.config._setupstate.addfinalizer(finalizer=finalizer, colitem=colitem)
|
||||
|
||||
def __repr__(self):
|
||||
return "<FuncargRequest %r for %r>" %(self.argname, self._pyfuncitem)
|
||||
return "<FuncargRequest for %r>" %(self._pyfuncitem)
|
||||
|
||||
def _raiselookupfailed(self):
|
||||
def _raiselookupfailed(self, argname):
|
||||
available = []
|
||||
for plugin in self._plugins:
|
||||
for name in vars(plugin):
|
||||
|
@ -146,7 +167,7 @@ class FuncargRequest:
|
|||
available.append(name)
|
||||
fspath, lineno, msg = self._pyfuncitem.reportinfo()
|
||||
line = "%s:%s" %(fspath, lineno)
|
||||
msg = "funcargument %r not found for: %s" %(self.argname, line)
|
||||
msg = "funcargument %r not found for: %s" %(argname, line)
|
||||
msg += "\n available funcargs: %s" %(", ".join(available),)
|
||||
raise LookupError(msg)
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@ def test_generic(plugintester):
|
|||
def test_funcarg(testdir):
|
||||
from py.__.test.funcargs import FuncargRequest
|
||||
item = testdir.getitem("def test_func(tmpdir): pass")
|
||||
p = pytest_funcarg__tmpdir(FuncargRequest(item, "tmpdir"))
|
||||
p = pytest_funcarg__tmpdir(FuncargRequest(item))
|
||||
assert p.check()
|
||||
bn = p.basename.strip("0123456789-")
|
||||
assert bn.endswith("test_func")
|
||||
|
|
|
@ -85,8 +85,7 @@ class TestRequest:
|
|||
def pytest_funcarg__something(request): pass
|
||||
def test_func(something): pass
|
||||
""")
|
||||
req = funcargs.FuncargRequest(item, argname="other")
|
||||
assert req.argname == "other"
|
||||
req = funcargs.FuncargRequest(item)
|
||||
assert req.function == item.obj
|
||||
assert hasattr(req.module, 'test_func')
|
||||
assert req.cls is None
|
||||
|
@ -100,46 +99,86 @@ class TestRequest:
|
|||
def test_func(self, something):
|
||||
pass
|
||||
""")
|
||||
req = funcargs.FuncargRequest(item, argname="something")
|
||||
req = funcargs.FuncargRequest(item)
|
||||
assert req.cls.__name__ == "TestB"
|
||||
assert req.instance.__class__ == req.cls
|
||||
|
||||
def test_request_contains_funcargs_provider(self, testdir):
|
||||
|
||||
def XXXtest_request_contains_funcargs_provider(self, testdir):
|
||||
modcol = testdir.getmodulecol("""
|
||||
def pytest_funcarg__something(request):
|
||||
pass
|
||||
class TestClass:
|
||||
def test_method(self, something):
|
||||
pass
|
||||
pass
|
||||
""")
|
||||
item1, = testdir.genitems([modcol])
|
||||
assert item1.name == "test_method"
|
||||
provider = funcargs.FuncargRequest(item1, "something")._provider
|
||||
provider = funcargs.FuncargRequest(item1)._provider
|
||||
assert len(provider) == 1
|
||||
assert provider[0].__name__ == "pytest_funcarg__something"
|
||||
|
||||
def test_request_call_next_provider(self, testdir):
|
||||
item = testdir.getitem("""
|
||||
def pytest_funcarg__something(request): pass
|
||||
def pytest_funcarg__something(request): return 1
|
||||
def test_func(something): pass
|
||||
""")
|
||||
req = funcargs.FuncargRequest(item, "something")
|
||||
val = req.call_next_provider()
|
||||
assert val is None
|
||||
req = funcargs.FuncargRequest(item)
|
||||
val = req.getfuncargvalue("something")
|
||||
assert val == 1
|
||||
py.test.raises(req.Error, "req.call_next_provider()")
|
||||
|
||||
def test_getfuncargvalue(self, testdir):
|
||||
item = testdir.getitem("""
|
||||
l = [2]
|
||||
def pytest_funcarg__something(request): return 1
|
||||
def pytest_funcarg__other(request):
|
||||
return l.pop()
|
||||
def test_func(something): pass
|
||||
""")
|
||||
req = funcargs.FuncargRequest(item)
|
||||
val = req.getfuncargvalue("something")
|
||||
assert val == 1
|
||||
val = req.getfuncargvalue("something")
|
||||
assert val == 1
|
||||
val2 = req.getfuncargvalue("other")
|
||||
assert val2 == 2
|
||||
val2 = req.getfuncargvalue("other") # see about caching
|
||||
assert val2 == 2
|
||||
req._fillfuncargs()
|
||||
assert item.funcargs == {'something': 1}
|
||||
|
||||
def test_request_addfinalizer(self, testdir):
|
||||
item = testdir.getitem("""
|
||||
def pytest_funcarg__something(request): pass
|
||||
def test_func(something): pass
|
||||
""")
|
||||
req = funcargs.FuncargRequest(item, "something")
|
||||
req = funcargs.FuncargRequest(item)
|
||||
py.test.raises(ValueError, "req.addfinalizer(None, scope='xyz')")
|
||||
l = [1]
|
||||
req.addfinalizer(l.pop)
|
||||
req.config._setupstate._teardown(item)
|
||||
assert not l
|
||||
|
||||
def test_request_getmodulepath(self, testdir):
|
||||
modcol = testdir.getmodulecol("def test_somefunc(): pass")
|
||||
item, = testdir.genitems([modcol])
|
||||
req = funcargs.FuncargRequest(item)
|
||||
assert req.fspath == modcol.fspath
|
||||
|
||||
class TestRequestProtocol:
|
||||
@py.test.mark.xfail
|
||||
def test_protocol(self, testdir):
|
||||
item = testdir.getitem("""
|
||||
def pytest_funcarg_arg1(request): return 1
|
||||
def pytest_funcarg_arg2(request): return 2
|
||||
def test_func(arg1, arg2): pass
|
||||
""")
|
||||
req = funcargs.FuncargRequest(item)
|
||||
req._fillargs()
|
||||
#assert item.funcreq.
|
||||
|
||||
|
||||
class TestRequestCachedSetup:
|
||||
def test_request_cachedsetup(self, testdir):
|
||||
item1,item2 = testdir.getitems("""
|
||||
class TestClass:
|
||||
|
@ -148,7 +187,7 @@ class TestRequest:
|
|||
def test_func2(self, something):
|
||||
pass
|
||||
""")
|
||||
req1 = funcargs.FuncargRequest(item1, "something")
|
||||
req1 = funcargs.FuncargRequest(item1)
|
||||
l = ["hello"]
|
||||
def setup():
|
||||
return l.pop()
|
||||
|
@ -156,13 +195,13 @@ class TestRequest:
|
|||
assert ret1 == "hello"
|
||||
ret1b = req1.cached_setup(setup)
|
||||
assert ret1 == ret1b
|
||||
req2 = funcargs.FuncargRequest(item2, "something")
|
||||
req2 = funcargs.FuncargRequest(item2)
|
||||
ret2 = req2.cached_setup(setup)
|
||||
assert ret2 == ret1
|
||||
|
||||
def test_request_cachedsetup_extrakey(self, testdir):
|
||||
item1 = testdir.getitem("def test_func(): pass")
|
||||
req1 = funcargs.FuncargRequest(item1, "something")
|
||||
req1 = funcargs.FuncargRequest(item1)
|
||||
l = ["hello", "world"]
|
||||
def setup():
|
||||
return l.pop()
|
||||
|
@ -202,11 +241,6 @@ class TestRequest:
|
|||
"*3 passed*"
|
||||
])
|
||||
|
||||
def test_request_getmodulepath(self, testdir):
|
||||
modcol = testdir.getmodulecol("def test_somefunc(): pass")
|
||||
item, = testdir.genitems([modcol])
|
||||
req = funcargs.FuncargRequest(item, "xxx")
|
||||
assert req.fspath == modcol.fspath
|
||||
|
||||
class TestMetafunc:
|
||||
def test_no_funcargs(self, testdir):
|
||||
|
|
|
@ -4,10 +4,10 @@ from py.__.test import parseopt
|
|||
pytest_plugins = 'pytest_iocapture'
|
||||
|
||||
class TestParser:
|
||||
def test_init(self, stdcapture):
|
||||
def test_init(self, capsys):
|
||||
parser = parseopt.Parser(usage="xyz")
|
||||
py.test.raises(SystemExit, 'parser.parse(["-h"])')
|
||||
out, err = stdcapture.reset()
|
||||
out, err = capsys.reset()
|
||||
assert out.find("xyz") != -1
|
||||
|
||||
def test_group_add_and_get(self):
|
||||
|
|
Loading…
Reference in New Issue