From 0cfd873abe37a47cf376422b7c50f8507e8cb5e9 Mon Sep 17 00:00:00 2001 From: Anatoly Bubenkov Date: Tue, 3 Dec 2013 21:05:19 +0100 Subject: [PATCH] implement index-based mechanizm for collection of parametrized tests --HG-- branch : parametrize-hashable --- CHANGELOG | 3 +++ _pytest/python.py | 25 +++++++++++++++---------- testing/python/collect.py | 29 +++++++++++++++++++++++++++++ 3 files changed, 47 insertions(+), 10 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 65e0f543566..2835b7ca347 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,9 @@ Unreleased ----------------------------------- +- fix issue244 by implementing special index for parameters to only use + indices for paramentrized test ids + - fix issue287 by running all finalizers but saving the exception from the first failing finalizer and re-raising it so teardown will still have failed. We reraise the first failing exception because diff --git a/_pytest/python.py b/_pytest/python.py index eeaa13ec986..1f669251cd7 100644 --- a/_pytest/python.py +++ b/_pytest/python.py @@ -594,12 +594,14 @@ def __init__(self, metafunc): self._globalparam = _notexists self._arg2scopenum = {} # used for sorting parametrized resources self.keywords = {} + self.indices = {} def copy(self, metafunc): cs = CallSpec2(self.metafunc) cs.funcargs.update(self.funcargs) cs.params.update(self.params) cs.keywords.update(self.keywords) + cs.indices.update(self.indices) cs._arg2scopenum.update(self._arg2scopenum) cs._idlist = list(self._idlist) cs._globalid = self._globalid @@ -623,7 +625,8 @@ def getparam(self, name): def id(self): return "-".join(map(str, filter(None, self._idlist))) - def setmulti(self, valtype, argnames, valset, id, keywords, scopenum=0): + def setmulti(self, valtype, argnames, valset, id, keywords, scopenum, + param_index): for arg,val in zip(argnames, valset): self._checkargnotcontained(arg) getattr(self, valtype)[arg] = val @@ -631,6 +634,7 @@ def setmulti(self, valtype, argnames, valset, id, keywords, scopenum=0): # parametrize_sorted() 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: self._emptyparamspecified = True @@ -740,11 +744,12 @@ def parametrize(self, argnames, argvalues, indirect=False, ids=None, ids = idmaker(argnames, argvalues) newcalls = [] for callspec in self._calls or [CallSpec2(self)]: - for i, valset in enumerate(argvalues): + for param_index, valset in enumerate(argvalues): assert len(valset) == len(argnames) newcallspec = callspec.copy(self) - newcallspec.setmulti(valtype, argnames, valset, ids[i], - newkeywords.get(i, {}), scopenum) + newcallspec.setmulti(valtype, argnames, valset, ids[param_index], + newkeywords.get(param_index, {}), scopenum, + param_index) newcalls.append(newcallspec) self._calls = newcalls @@ -1862,19 +1867,19 @@ def getfuncargparams(item, ignore, scopenum, cache): except AttributeError: return [] if scopenum == 0: - argparams = [x for x in cs.params.items() if x not in ignore + argparams = [x for x in cs.indices.items() if x not in ignore and cs._arg2scopenum[x[0]] == scopenum] elif scopenum == 1: # module argparams = [] - for argname, param in cs.params.items(): + for argname, valindex in cs.indices.items(): if cs._arg2scopenum[argname] == scopenum: - key = (argname, param, item.fspath) + key = (argname, valindex, item.fspath) if key in ignore: continue argparams.append(key) elif scopenum == 2: # class argparams = [] - for argname, param in cs.params.items(): + for argname, valindex in cs.indices.items(): if cs._arg2scopenum[argname] == scopenum: l = cache.setdefault(item.fspath, []) try: @@ -1882,13 +1887,13 @@ def getfuncargparams(item, ignore, scopenum, cache): except ValueError: i = len(l) l.append(item.cls) - key = (argname, param, item.fspath, i) + key = (argname, valindex, item.fspath, i) if key in ignore: continue argparams.append(key) #elif scopenum == 3: # argparams = [] - # for argname, param in cs.params.items(): + # for argname, param in cs.indices.items(): # if cs._arg2scopenum[argname] == scopenum: # key = (argname, param, getfslineno(item.obj)) # if key in ignore: diff --git a/testing/python/collect.py b/testing/python/collect.py index 62ce6fc37c1..c68c9a84e6e 100644 --- a/testing/python/collect.py +++ b/testing/python/collect.py @@ -355,6 +355,35 @@ def test_archival_to_version(key, value): rec = testdir.inline_run() rec.assertoutcome(passed=2) + + def test_parametrize_with_non_hashable_values_indirect(self, testdir): + """Test parametrization with non-hashable values with indirect parametrization.""" + testdir.makepyfile(""" + archival_mapping = { + '1.0': {'tag': '1.0'}, + '1.2.2a1': {'tag': 'release-1.2.2a1'}, + } + + import pytest + + @pytest.fixture + def key(request): + return request.param + + @pytest.fixture + def value(request): + return request.param + + @pytest.mark.parametrize('key value'.split(), + archival_mapping.items(), indirect=True) + def test_archival_to_version(key, value): + assert key in archival_mapping + assert value == archival_mapping[key] + """) + rec = testdir.inline_run() + rec.assertoutcome(passed=2) + + def test_parametrize_with_mark(selfself, testdir): items = testdir.getitems(""" import pytest