[Pytest-commit] commit/pytest: 2 new changesets
commits-noreply at bitbucket.org
commits-noreply at bitbucket.org
Sat Dec 7 16:37:57 CET 2013
2 new commits in pytest:
https://bitbucket.org/hpk42/pytest/commits/74c6f671db35/
Changeset: 74c6f671db35
User: hpk42
Date: 2013-12-05 14:40:50
Summary: remove unused line
Affected #: 1 file
diff -r 1338c1ed28ffbeda49a7a9dbf983de8b569f52db -r 74c6f671db35765fd4bfe51685a8ac015fd9ede7 _pytest/python.py
--- a/_pytest/python.py
+++ b/_pytest/python.py
@@ -1081,8 +1081,6 @@
def __init__(self, pyfuncitem):
self._pyfuncitem = pyfuncitem
- if hasattr(pyfuncitem, '_requestparam'):
- self.param = pyfuncitem._requestparam
#: fixture for which this request is being performed
self.fixturename = None
#: Scope string, one of "function", "cls", "module", "session"
https://bitbucket.org/hpk42/pytest/commits/25ca40a219a0/
Changeset: 25ca40a219a0
User: hpk42
Date: 2013-12-07 16:37:46
Summary: refactor internal finalization mechanics such that all fixture arguments
in a test invocation will have a corresponding FixtureDef instance.
also fixes issue246 (again).
simplify parametrized fixture teardown by making it work lazy:
during the setup of a parametrized fixture instance any previously
setup instance which was setup with a different param is torn down
before setting up the new one.
Affected #: 7 files
diff -r 74c6f671db35765fd4bfe51685a8ac015fd9ede7 -r 25ca40a219a02a9451e7f9cb4c3273a41499f331 CHANGELOG
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,6 +1,19 @@
Unreleased
-----------------------------------
+- simplified and fixed implementation for calling finalizers when
+ parametrized fixtures or function arguments are involved. finalization
+ is now performed lazily at setup time instead of in the "teardown phase".
+ While this might sound odd at first, it helps to ensure that we are
+ correctly handling setup/teardown even in complex code. User-level code
+ should not be affected unless it's implementing the pytest_runtest_teardown
+ hook and expecting certain fixture instances are torn down within (very
+ unlikely and would have been unreliable anyway).
+
+- fix issue246 (again) fix finalizer order to be LIFO on independent fixtures
+ depending on a parametrized higher-than-function scoped fixture.
+ (fix quite some effort so please bear with the complexity of this sentence :)
+
- fix issue244 by implementing special index for parameters to only use
indices for paramentrized test ids
diff -r 74c6f671db35765fd4bfe51685a8ac015fd9ede7 -r 25ca40a219a02a9451e7f9cb4c3273a41499f331 _pytest/main.py
--- a/_pytest/main.py
+++ b/_pytest/main.py
@@ -230,6 +230,8 @@
#: allow adding of extra keywords to use for matching
self.extra_keyword_matches = set()
+ # used for storing artificial fixturedefs for direct parametrization
+ self._name2pseudofixturedef = {}
#self.extrainit()
@property
@@ -365,6 +367,8 @@
self.session._setupstate.addfinalizer(fin, self)
def getparent(self, cls):
+ """ get the next parent node (including ourself)
+ which is an instance of the given class"""
current = self
while current and not isinstance(current, cls):
current = current.parent
diff -r 74c6f671db35765fd4bfe51685a8ac015fd9ede7 -r 25ca40a219a02a9451e7f9cb4c3273a41499f331 _pytest/python.py
--- a/_pytest/python.py
+++ b/_pytest/python.py
@@ -341,12 +341,72 @@
if not metafunc._calls:
yield Function(name, parent=self)
else:
+ # add funcargs() as fixturedefs to fixtureinfo.arg2fixturedefs
+ add_funcarg_pseudo_fixture_def(self, metafunc, fm)
+
for callspec in metafunc._calls:
subname = "%s[%s]" %(name, callspec.id)
yield Function(name=subname, parent=self,
callspec=callspec, callobj=funcobj,
keywords={callspec.id:True})
+def add_funcarg_pseudo_fixture_def(collector, metafunc, fixturemanager):
+ # this function will transform all collected calls to a functions
+ # if they use direct funcargs (i.e. direct parametrization)
+ # because we want later test execution to be able to rely on
+ # an existing FixtureDef structure for all arguments.
+ # XXX we can probably avoid this algorithm if we modify CallSpec2
+ # to directly care for creating the fixturedefs within its methods.
+ if not metafunc._calls[0].funcargs:
+ return # this function call does not have direct parametrization
+ # collect funcargs of all callspecs into a list of values
+ arg2params = {}
+ arg2scope = {}
+ arg2fixturedefs = metafunc._arg2fixturedefs
+ for param_index, callspec in enumerate(metafunc._calls):
+ for argname, argvalue in callspec.funcargs.items():
+ assert argname not in arg2fixturedefs
+ arg2params.setdefault(argname, []).append(argvalue)
+ if argname not in arg2scope:
+ scopenum = callspec._arg2scopenum.get(argname, scopenum_function)
+ arg2scope[argname] = scopes[scopenum]
+ callspec.indices[argname] = param_index
+
+ for argname in callspec.funcargs:
+ assert argname not in callspec.params
+ callspec.params.update(callspec.funcargs)
+ callspec.funcargs.clear()
+
+ # register artificial FixtureDef's so that later at test execution
+ # time we can rely on a proper FixtureDef to exist for fixture setup.
+ for argname, valuelist in arg2params.items():
+ # if we have a scope that is higher than function we need
+ # to make sure we only ever create an according fixturedef on
+ # a per-scope basis. We thus store and cache the fixturedef on the
+ # node related to the scope.
+ assert argname not in arg2fixturedefs, (argname, arg2fixturedefs)
+ scope = arg2scope[argname]
+ node = None
+ if scope != "function":
+ node = get_scope_node(collector, scope)
+ if node is None:
+ assert scope == "class" and isinstance(collector, Module)
+ # use module-level collector for class-scope (for now)
+ node = collector
+ if node and argname in node._name2pseudofixturedef:
+ arg2fixturedefs[argname] = [node._name2pseudofixturedef[argname]]
+ else:
+ fixturedef = FixtureDef(fixturemanager, '', argname,
+ get_direct_param_fixture_func,
+ arg2scope[argname],
+ valuelist, False, False)
+ arg2fixturedefs[argname] = [fixturedef]
+ if node is not None:
+ node._name2pseudofixturedef[argname] = fixturedef
+
+
+def get_direct_param_fixture_func(request):
+ return request.param
class FuncFixtureInfo:
def __init__(self, argnames, names_closure, name2fixturedefs):
@@ -560,25 +620,24 @@
def fillfixtures(function):
""" fill missing funcargs for a test function. """
- if 1 or getattr(function, "_args", None) is None: # not a yielded function
- try:
- request = function._request
- except AttributeError:
- # XXX this special code path is only expected to execute
- # with the oejskit plugin. It uses classes with funcargs
- # and we thus have to work a bit to allow this.
- fm = function.session._fixturemanager
- fi = fm.getfixtureinfo(function.parent, function.obj, None)
- function._fixtureinfo = fi
- request = function._request = FixtureRequest(function)
- request._fillfixtures()
- # prune out funcargs for jstests
- newfuncargs = {}
- for name in fi.argnames:
- newfuncargs[name] = function.funcargs[name]
- function.funcargs = newfuncargs
- else:
- request._fillfixtures()
+ try:
+ request = function._request
+ except AttributeError:
+ # XXX this special code path is only expected to execute
+ # with the oejskit plugin. It uses classes with funcargs
+ # and we thus have to work a bit to allow this.
+ fm = function.session._fixturemanager
+ fi = fm.getfixtureinfo(function.parent, function.obj, None)
+ function._fixtureinfo = fi
+ request = function._request = FixtureRequest(function)
+ request._fillfixtures()
+ # prune out funcargs for jstests
+ newfuncargs = {}
+ for name in fi.argnames:
+ newfuncargs[name] = function.funcargs[name]
+ function.funcargs = newfuncargs
+ else:
+ request._fillfixtures()
_notexists = object()
@@ -630,10 +689,6 @@
for arg,val in zip(argnames, valset):
self._checkargnotcontained(arg)
getattr(self, valtype)[arg] = val
- # we want self.params to be always set because of
- # reorder_items() which groups tests by params/scope
- if valtype == "funcargs":
- self.params[arg] = id
self.indices[arg] = param_index
self._arg2scopenum[arg] = scopenum
if val is _notexists:
@@ -650,6 +705,8 @@
if param is not _notexists:
assert self._globalparam is _notexists
self._globalparam = param
+ for arg in funcargs:
+ self._arg2scopenum[arg] = scopenum_function
class FuncargnamesCompatAttr:
@@ -728,7 +785,7 @@
argvalues = [(_notexists,) * len(argnames)]
if scope is None:
- scope = "subfunction"
+ scope = "function"
scopenum = scopes.index(scope)
if not indirect:
#XXX should we also check for the opposite case?
@@ -971,30 +1028,26 @@
for name, val in keywords.items():
self.keywords[name] = val
- fm = self.session._fixturemanager
isyield = self._isyieldedfunction()
- self._fixtureinfo = fi = fm.getfixtureinfo(self.parent, self.obj,
- self.cls,
- funcargs=not isyield)
+ self._fixtureinfo = fi = self.session._fixturemanager.getfixtureinfo(
+ self.parent, self.obj, self.cls, funcargs=not isyield)
self.fixturenames = fi.names_closure
if callspec is not None:
self.callspec = callspec
self._initrequest()
def _initrequest(self):
+ self.funcargs = {}
if self._isyieldedfunction():
assert not hasattr(self, "callspec"), (
"yielded functions (deprecated) cannot have funcargs")
- self.funcargs = {}
else:
if hasattr(self, "callspec"):
callspec = self.callspec
- self.funcargs = callspec.funcargs.copy()
+ assert not callspec.funcargs
self._genid = callspec.id
if hasattr(callspec, "param"):
self.param = callspec.param
- else:
- self.funcargs = {}
self._request = FixtureRequest(self)
@property
@@ -1085,9 +1138,10 @@
self.fixturename = None
#: Scope string, one of "function", "cls", "module", "session"
self.scope = "function"
- self._funcargs = self._pyfuncitem.funcargs.copy()
+ self._funcargs = {}
+ self._fixturedefs = {}
fixtureinfo = pyfuncitem._fixtureinfo
- self._arg2fixturedefs = fixtureinfo.name2fixturedefs
+ self._arg2fixturedefs = fixtureinfo.name2fixturedefs.copy()
self._arg2index = {}
self.fixturenames = fixtureinfo.names_closure
self._fixturemanager = pyfuncitem.session._fixturemanager
@@ -1097,15 +1151,17 @@
""" underlying collection node (depends on current request scope)"""
return self._getscopeitem(self.scope)
+
def _getnextfixturedef(self, argname):
fixturedefs = self._arg2fixturedefs.get(argname, None)
if fixturedefs is None:
- # we arrive here because of a getfuncargvalue(argname) usage which
- # was naturally not knowable at parsing/collection time
+ # we arrive here because of a a dynamic call to
+ # getfuncargvalue(argname) usage which was naturally
+ # not known at parsing/collection time
fixturedefs = self._fixturemanager.getfixturedefs(
argname, self._pyfuncitem.parent.nodeid)
self._arg2fixturedefs[argname] = fixturedefs
- # fixturedefs is immutable so we maintain a decreasing index
+ # fixturedefs list is immutable so we maintain a decreasing index
index = self._arg2index.get(argname, 0) - 1
if fixturedefs is None or (-index > len(fixturedefs)):
raise FixtureLookupError(argname, self)
@@ -1137,7 +1193,9 @@
try:
return self._pyfuncitem._testcase
except AttributeError:
- return py.builtin._getimself(self.function)
+ function = getattr(self, "function", None)
+ if function is not None:
+ return py.builtin._getimself(function)
@scopeproperty()
def module(self):
@@ -1167,12 +1225,7 @@
self._addfinalizer(finalizer, scope=self.scope)
def _addfinalizer(self, finalizer, scope):
- if scope != "function" and hasattr(self, "param"):
- # parametrized resources are sorted by param
- # so we rather store finalizers per (argname, param)
- colitem = (self.fixturename, self.param)
- else:
- colitem = self._getscopeitem(scope)
+ colitem = self._getscopeitem(scope)
self._pyfuncitem.session._setupstate.addfinalizer(
finalizer=finalizer, colitem=colitem)
@@ -1246,19 +1299,24 @@
setup time, you may use this function to retrieve it inside a fixture
function body.
"""
+ return self._get_active_fixturedef(argname).cached_result[0]
+
+ def _get_active_fixturedef(self, argname):
try:
- return self._funcargs[argname]
+ return self._fixturedefs[argname]
except KeyError:
- pass
- try:
- fixturedef = self._getnextfixturedef(argname)
- except FixtureLookupError:
- if argname == "request":
- return self
- raise
- result = self._getfuncargvalue(fixturedef)
- self._funcargs[argname] = result
- return result
+ try:
+ fixturedef = self._getnextfixturedef(argname)
+ except FixtureLookupError:
+ if argname == "request":
+ class PseudoFixtureDef:
+ cached_result = (self, [0])
+ return PseudoFixtureDef
+ raise
+ result = self._getfuncargvalue(fixturedef)
+ self._funcargs[argname] = result
+ self._fixturedefs[argname] = fixturedef
+ return fixturedef
def _get_fixturestack(self):
current = self
@@ -1272,28 +1330,26 @@
current = current._parent_request
def _getfuncargvalue(self, fixturedef):
- try:
- return fixturedef.cached_result # set by fixturedef.execute()
- except AttributeError:
- pass
# prepare a subrequest object before calling fixture function
# (latter managed by fixturedef)
argname = fixturedef.argname
- node = self._pyfuncitem
+ funcitem = self._pyfuncitem
scope = fixturedef.scope
try:
- param = node.callspec.getparam(argname)
+ param = funcitem.callspec.getparam(argname)
except (AttributeError, ValueError):
param = NOTSET
+ param_index = 0
else:
+ # indices might not be set if old-style metafunc.addcall() was used
+ param_index = funcitem.callspec.indices.get(argname, 0)
# if a parametrize invocation set a scope it will override
# the static scope defined with the fixture function
- paramscopenum = node.callspec._arg2scopenum.get(argname)
- if paramscopenum is not None and \
- paramscopenum != scopenum_subfunction:
+ paramscopenum = funcitem.callspec._arg2scopenum.get(argname)
+ if paramscopenum is not None:
scope = scopes[paramscopenum]
- subrequest = SubRequest(self, scope, param, fixturedef)
+ subrequest = SubRequest(self, scope, param, param_index, fixturedef)
# check if a higher-level scoped fixture accesses a lower level one
if scope is not None:
@@ -1308,19 +1364,12 @@
__tracebackhide__ = False
try:
- # perform the fixture call
+ # call the fixture function
val = fixturedef.execute(request=subrequest)
finally:
- # if the fixture function failed it might still have
- # registered finalizers so we can register
- # prepare finalization according to scope
- # (XXX analyse exact finalizing mechanics / cleanup)
+ # if fixture function failed it might have registered finalizers
self.session._setupstate.addfinalizer(fixturedef.finish,
subrequest.node)
- self._fixturemanager.addargfinalizer(fixturedef.finish, argname)
- for subargname in fixturedef.argnames: # XXX all deps?
- self._fixturemanager.addargfinalizer(fixturedef.finish,
- subargname)
return val
def _factorytraceback(self):
@@ -1336,18 +1385,14 @@
def _getscopeitem(self, scope):
if scope == "function":
+ # this might also be a non-function Item despite its attribute name
return self._pyfuncitem
- elif scope == "session":
- return self.session
- elif scope == "class":
- x = self._pyfuncitem.getparent(pytest.Class)
- if x is not None:
- return x
- # fallback to function
- return self._pyfuncitem
- if scope == "module":
- return self._pyfuncitem.getparent(pytest.Module)
- raise ValueError("unknown finalization scope %r" %(scope,))
+ node = get_scope_node(self._pyfuncitem, scope)
+ if node is None and scope == "class":
+ # fallback to function item itself
+ node = self._pyfuncitem
+ assert node
+ return node
def __repr__(self):
return "<FixtureRequest for %r>" %(self.node)
@@ -1356,16 +1401,18 @@
class SubRequest(FixtureRequest):
""" a sub request for handling getting a fixture from a
test function/fixture. """
- def __init__(self, request, scope, param, fixturedef):
+ def __init__(self, request, scope, param, param_index, fixturedef):
self._parent_request = request
self.fixturename = fixturedef.argname
if param is not NOTSET:
self.param = param
+ self.param_index = param_index
self.scope = scope
self._fixturedef = fixturedef
self.addfinalizer = fixturedef.addfinalizer
self._pyfuncitem = request._pyfuncitem
self._funcargs = request._funcargs
+ self._fixturedefs = request._fixturedefs
self._arg2fixturedefs = request._arg2fixturedefs
self._arg2index = request._arg2index
self.fixturenames = request.fixturenames
@@ -1380,8 +1427,7 @@
which has a lower scope (e.g. a Session one calls a function one)
"""
-scopes = "session module class function subfunction".split()
-scopenum_subfunction = scopes.index("subfunction")
+scopes = "session module class function".split()
scopenum_function = scopes.index("function")
def scopemismatch(currentscope, newscope):
return scopes.index(newscope) > scopes.index(currentscope)
@@ -1581,14 +1627,14 @@
if argname in arg2fixturedefs:
continue
fixturedefs = self.getfixturedefs(argname, parentid)
- arg2fixturedefs[argname] = fixturedefs
if fixturedefs:
+ arg2fixturedefs[argname] = fixturedefs
merge(fixturedefs[-1].argnames)
return fixturenames_closure, arg2fixturedefs
def pytest_generate_tests(self, metafunc):
for argname in metafunc.fixturenames:
- faclist = metafunc._arg2fixturedefs[argname]
+ faclist = metafunc._arg2fixturedefs.get(argname)
if faclist is None:
continue # will raise FixtureLookupError at setup time
for fixturedef in faclist:
@@ -1600,38 +1646,6 @@
# separate parametrized setups
items[:] = reorder_items(items, set(), {}, 0)
- @pytest.mark.trylast
- def pytest_runtest_teardown(self, item, nextitem):
- # XXX teardown needs to be normalized for parametrized and
- # no-parametrized functions
- try:
- cs1 = item.callspec
- except AttributeError:
- return
-
- # determine which fixtures are not needed anymore for the next test
- keylist = []
- for name in cs1.params:
- try:
- if name in nextitem.callspec.params and \
- cs1.params[name] == nextitem.callspec.params[name]:
- continue
- except AttributeError:
- pass
- key = (-cs1._arg2scopenum[name], name, cs1.params[name])
- keylist.append(key)
-
- # sort by scope (function scope first, then higher ones)
- keylist.sort()
- for (scopenum, name, param) in keylist:
- #if -scopenum >= scopenum_function:
- # continue # handled by runner.pytest_runtest_teardown
- item.session._setupstate._callfinalizers((name, param))
- l = self._arg2finish.pop(name, None)
- if l is not None:
- for fin in reversed(l):
- fin()
-
def parsefactories(self, node_or_obj, nodeid=NOTSET, unittest=False):
if nodeid is not NOTSET:
holderobj = node_or_obj
@@ -1693,16 +1707,6 @@
if nodeid.startswith(fixturedef.baseid):
yield fixturedef
- def addargfinalizer(self, finalizer, argname):
- l = self._arg2finish.setdefault(argname, [])
- l.append(finalizer)
-
- def removefinalizer(self, finalizer):
- for l in self._arg2finish.values():
- try:
- l.remove(finalizer)
- except ValueError:
- pass
def fail_fixturefunc(fixturefunc, msg):
fs, lineno = getfslineno(fixturefunc)
@@ -1764,41 +1768,56 @@
while self._finalizer:
func = self._finalizer.pop()
func()
- # check neccesity of next commented call
- self._fixturemanager.removefinalizer(self.finish)
try:
del self.cached_result
except AttributeError:
pass
def execute(self, request):
+ # get required arguments and register our own finish()
+ # with their finalization
kwargs = {}
- for newname in self.argnames:
- kwargs[newname] = request.getfuncargvalue(newname)
+ for argname in self.argnames:
+ fixturedef = request._get_active_fixturedef(argname)
+ result, arg_cache_key = fixturedef.cached_result
+ kwargs[argname] = result
+ if argname != "request":
+ fixturedef.addfinalizer(self.finish)
+
+ my_cache_key = request.param_index
+ cached_result = getattr(self, "cached_result", None)
+ if cached_result is not None:
+ #print argname, "Found cached_result", cached_result
+ #print argname, "param_index", param_index
+ result, cache_key = cached_result
+ if my_cache_key == cache_key:
+ #print request.fixturename, "CACHE HIT", repr(my_cache_key)
+ return result
+ #print request.fixturename, "CACHE MISS"
+ # we have a previous but differently parametrized fixture instance
+ # so we need to tear it down before creating a new one
+ self.finish()
+ assert not hasattr(self, "cached_result")
+
if self.unittest:
result = self.func(request.instance, **kwargs)
else:
fixturefunc = self.func
# the fixture function needs to be bound to the actual
# request.instance so that code working with "self" behaves
- # as expected. XXX request.instance should maybe return None
- # instead of raising AttributeError
- try:
- if request.instance is not None:
- fixturefunc = getimfunc(self.func)
- if fixturefunc != self.func:
- fixturefunc = fixturefunc.__get__(request.instance)
- except AttributeError:
- pass
+ # as expected.
+ if request.instance is not None:
+ fixturefunc = getimfunc(self.func)
+ if fixturefunc != self.func:
+ fixturefunc = fixturefunc.__get__(request.instance)
result = call_fixture_func(fixturefunc, request, kwargs,
self.yieldctx)
- assert not hasattr(self, "cached_result")
- self.cached_result = result
+ self.cached_result = (result, my_cache_key)
return result
def __repr__(self):
- return ("<FixtureDef name=%r scope=%r baseid=%r module=%r>" %
- (self.argname, self.scope, self.baseid, self.func.__module__))
+ return ("<FixtureDef name=%r scope=%r baseid=%r >" %
+ (self.argname, self.scope, self.baseid))
def getfuncargnames(function, startindex=None):
# XXX merge with main.py's varnames
@@ -1910,3 +1929,15 @@
# we don't expect them to be fixture functions
return None
+scopename2class = {
+ 'class': Class,
+ 'module': Module,
+ 'function': pytest.Item,
+}
+def get_scope_node(node, scope):
+ cls = scopename2class.get(scope)
+ if cls is None:
+ if scope == "session":
+ return node.session
+ raise ValueError("unknown scope")
+ return node.getparent(cls)
diff -r 74c6f671db35765fd4bfe51685a8ac015fd9ede7 -r 25ca40a219a02a9451e7f9cb4c3273a41499f331 testing/python/collect.py
--- a/testing/python/collect.py
+++ b/testing/python/collect.py
@@ -334,7 +334,7 @@
def test_function(arg):
assert arg.__class__.__name__ == "A"
""")
- reprec = testdir.inline_run()
+ reprec = testdir.inline_run("--fulltrace")
reprec.assertoutcome(passed=1)
def test_parametrize_with_non_hashable_values(self, testdir):
diff -r 74c6f671db35765fd4bfe51685a8ac015fd9ede7 -r 25ca40a219a02a9451e7f9cb4c3273a41499f331 testing/python/fixture.py
--- a/testing/python/fixture.py
+++ b/testing/python/fixture.py
@@ -1315,6 +1315,7 @@
l.append("step2-%d" % item)
def test_finish():
+ print (l)
assert l == ["setup-1", "step1-1", "step2-1", "teardown-1",
"setup-2", "step1-2", "step2-2", "teardown-2",]
""")
@@ -1683,23 +1684,22 @@
l.append("test3")
def test_4(modarg, arg):
l.append("test4")
- def test_5():
- assert len(l) == 12 * 3
- expected = [
- 'create:1', 'test1', 'fin:1', 'create:2', 'test1',
- 'fin:2', 'create:mod1', 'test2', 'create:1', 'test3',
- 'fin:1', 'create:2', 'test3', 'fin:2', 'create:1',
- 'test4', 'fin:1', 'create:2', 'test4', 'fin:2',
- 'fin:mod1', 'create:mod2', 'test2', 'create:1', 'test3',
- 'fin:1', 'create:2', 'test3', 'fin:2', 'create:1',
- 'test4', 'fin:1', 'create:2', 'test4', 'fin:2',
- 'fin:mod2']
- import pprint
- pprint.pprint(list(zip(l, expected)))
- assert l == expected
""")
reprec = testdir.inline_run("-v")
- reprec.assertoutcome(passed=12+1)
+ reprec.assertoutcome(passed=12)
+ l = reprec.getcalls("pytest_runtest_call")[0].item.module.l
+ expected = [
+ 'create:1', 'test1', 'fin:1', 'create:2', 'test1',
+ 'fin:2', 'create:mod1', 'test2', 'create:1', 'test3',
+ 'fin:1', 'create:2', 'test3', 'fin:2', 'create:1',
+ 'test4', 'fin:1', 'create:2', 'test4', 'fin:2',
+ 'fin:mod1', 'create:mod2', 'test2', 'create:1', 'test3',
+ 'fin:1', 'create:2', 'test3', 'fin:2', 'create:1',
+ 'test4', 'fin:1', 'create:2', 'test4', 'fin:2',
+ 'fin:mod2']
+ import pprint
+ pprint.pprint(list(zip(l, expected)))
+ assert l == expected
def test_parametrized_fixture_teardown_order(self, testdir):
testdir.makepyfile("""
@@ -1855,7 +1855,6 @@
reprec.assertoutcome(passed=5)
- @pytest.mark.xfail
@pytest.mark.issue246
@pytest.mark.parametrize("scope", ["session", "function", "module"])
def test_finalizer_order_on_parametrization(self, scope, testdir):
diff -r 74c6f671db35765fd4bfe51685a8ac015fd9ede7 -r 25ca40a219a02a9451e7f9cb4c3273a41499f331 testing/python/metafunc.py
--- a/testing/python/metafunc.py
+++ b/testing/python/metafunc.py
@@ -193,8 +193,8 @@
metafunc.parametrize('y', [2])
def pytest_funcarg__x(request):
return request.param * 10
- def pytest_funcarg__y(request):
- return request.param
+ #def pytest_funcarg__y(request):
+ # return request.param
def test_simple(x,y):
assert x in (10,20)
diff -r 74c6f671db35765fd4bfe51685a8ac015fd9ede7 -r 25ca40a219a02a9451e7f9cb4c3273a41499f331 tox.ini
--- a/tox.ini
+++ b/tox.ini
@@ -115,7 +115,7 @@
minversion=2.0
plugins=pytester
#--pyargs --doctest-modules --ignore=.tox
-addopts= -rxs
+addopts= -rxsX
rsyncdirs=tox.ini pytest.py _pytest testing
python_files=test_*.py *_test.py testing/*/*.py
python_classes=Test Acceptance
Repository URL: https://bitbucket.org/hpk42/pytest/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
More information about the pytest-commit
mailing list