Merged in paylogic/pytest/parametrize-hashable (pull request #89)
implement index-based mechanizm for collection of parametrized tests
This commit is contained in:
		
						commit
						bd320951e6
					
				| 
						 | 
					@ -1,6 +1,9 @@
 | 
				
			||||||
Unreleased
 | 
					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
 | 
					- fix issue287 by running all finalizers but saving the exception
 | 
				
			||||||
  from the first failing finalizer and re-raising it so teardown will
 | 
					  from the first failing finalizer and re-raising it so teardown will
 | 
				
			||||||
  still have failed.  We reraise the first failing exception because
 | 
					  still have failed.  We reraise the first failing exception because
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -594,12 +594,14 @@ class CallSpec2(object):
 | 
				
			||||||
        self._globalparam = _notexists
 | 
					        self._globalparam = _notexists
 | 
				
			||||||
        self._arg2scopenum = {}  # used for sorting parametrized resources
 | 
					        self._arg2scopenum = {}  # used for sorting parametrized resources
 | 
				
			||||||
        self.keywords = {}
 | 
					        self.keywords = {}
 | 
				
			||||||
 | 
					        self.indices = {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def copy(self, metafunc):
 | 
					    def copy(self, metafunc):
 | 
				
			||||||
        cs = CallSpec2(self.metafunc)
 | 
					        cs = CallSpec2(self.metafunc)
 | 
				
			||||||
        cs.funcargs.update(self.funcargs)
 | 
					        cs.funcargs.update(self.funcargs)
 | 
				
			||||||
        cs.params.update(self.params)
 | 
					        cs.params.update(self.params)
 | 
				
			||||||
        cs.keywords.update(self.keywords)
 | 
					        cs.keywords.update(self.keywords)
 | 
				
			||||||
 | 
					        cs.indices.update(self.indices)
 | 
				
			||||||
        cs._arg2scopenum.update(self._arg2scopenum)
 | 
					        cs._arg2scopenum.update(self._arg2scopenum)
 | 
				
			||||||
        cs._idlist = list(self._idlist)
 | 
					        cs._idlist = list(self._idlist)
 | 
				
			||||||
        cs._globalid = self._globalid
 | 
					        cs._globalid = self._globalid
 | 
				
			||||||
| 
						 | 
					@ -623,7 +625,8 @@ class CallSpec2(object):
 | 
				
			||||||
    def id(self):
 | 
					    def id(self):
 | 
				
			||||||
        return "-".join(map(str, filter(None, self._idlist)))
 | 
					        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):
 | 
					        for arg,val in zip(argnames, valset):
 | 
				
			||||||
            self._checkargnotcontained(arg)
 | 
					            self._checkargnotcontained(arg)
 | 
				
			||||||
            getattr(self, valtype)[arg] = val
 | 
					            getattr(self, valtype)[arg] = val
 | 
				
			||||||
| 
						 | 
					@ -631,6 +634,7 @@ class CallSpec2(object):
 | 
				
			||||||
            # parametrize_sorted() which groups tests by params/scope
 | 
					            # parametrize_sorted() which groups tests by params/scope
 | 
				
			||||||
            if valtype == "funcargs":
 | 
					            if valtype == "funcargs":
 | 
				
			||||||
                self.params[arg] = id
 | 
					                self.params[arg] = id
 | 
				
			||||||
 | 
					            self.indices[arg] = param_index
 | 
				
			||||||
            self._arg2scopenum[arg] = scopenum
 | 
					            self._arg2scopenum[arg] = scopenum
 | 
				
			||||||
            if val is _notexists:
 | 
					            if val is _notexists:
 | 
				
			||||||
                self._emptyparamspecified = True
 | 
					                self._emptyparamspecified = True
 | 
				
			||||||
| 
						 | 
					@ -740,11 +744,12 @@ class Metafunc(FuncargnamesCompatAttr):
 | 
				
			||||||
            ids = idmaker(argnames, argvalues)
 | 
					            ids = idmaker(argnames, argvalues)
 | 
				
			||||||
        newcalls = []
 | 
					        newcalls = []
 | 
				
			||||||
        for callspec in self._calls or [CallSpec2(self)]:
 | 
					        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)
 | 
					                assert len(valset) == len(argnames)
 | 
				
			||||||
                newcallspec = callspec.copy(self)
 | 
					                newcallspec = callspec.copy(self)
 | 
				
			||||||
                newcallspec.setmulti(valtype, argnames, valset, ids[i],
 | 
					                newcallspec.setmulti(valtype, argnames, valset, ids[param_index],
 | 
				
			||||||
                                     newkeywords.get(i, {}), scopenum)
 | 
					                                     newkeywords.get(param_index, {}), scopenum,
 | 
				
			||||||
 | 
					                                     param_index)
 | 
				
			||||||
                newcalls.append(newcallspec)
 | 
					                newcalls.append(newcallspec)
 | 
				
			||||||
        self._calls = newcalls
 | 
					        self._calls = newcalls
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1862,19 +1867,19 @@ def getfuncargparams(item, ignore, scopenum, cache):
 | 
				
			||||||
    except AttributeError:
 | 
					    except AttributeError:
 | 
				
			||||||
        return []
 | 
					        return []
 | 
				
			||||||
    if scopenum == 0:
 | 
					    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]
 | 
					                        and cs._arg2scopenum[x[0]] == scopenum]
 | 
				
			||||||
    elif scopenum == 1:  # module
 | 
					    elif scopenum == 1:  # module
 | 
				
			||||||
        argparams = []
 | 
					        argparams = []
 | 
				
			||||||
        for argname, param in cs.params.items():
 | 
					        for argname, valindex in cs.indices.items():
 | 
				
			||||||
            if cs._arg2scopenum[argname] == scopenum:
 | 
					            if cs._arg2scopenum[argname] == scopenum:
 | 
				
			||||||
                key = (argname, param, item.fspath)
 | 
					                key = (argname, valindex, item.fspath)
 | 
				
			||||||
                if key in ignore:
 | 
					                if key in ignore:
 | 
				
			||||||
                    continue
 | 
					                    continue
 | 
				
			||||||
                argparams.append(key)
 | 
					                argparams.append(key)
 | 
				
			||||||
    elif scopenum == 2:  # class
 | 
					    elif scopenum == 2:  # class
 | 
				
			||||||
        argparams = []
 | 
					        argparams = []
 | 
				
			||||||
        for argname, param in cs.params.items():
 | 
					        for argname, valindex in cs.indices.items():
 | 
				
			||||||
            if cs._arg2scopenum[argname] == scopenum:
 | 
					            if cs._arg2scopenum[argname] == scopenum:
 | 
				
			||||||
                l = cache.setdefault(item.fspath, [])
 | 
					                l = cache.setdefault(item.fspath, [])
 | 
				
			||||||
                try:
 | 
					                try:
 | 
				
			||||||
| 
						 | 
					@ -1882,13 +1887,13 @@ def getfuncargparams(item, ignore, scopenum, cache):
 | 
				
			||||||
                except ValueError:
 | 
					                except ValueError:
 | 
				
			||||||
                    i = len(l)
 | 
					                    i = len(l)
 | 
				
			||||||
                    l.append(item.cls)
 | 
					                    l.append(item.cls)
 | 
				
			||||||
                key = (argname, param, item.fspath, i)
 | 
					                key = (argname, valindex, item.fspath, i)
 | 
				
			||||||
                if key in ignore:
 | 
					                if key in ignore:
 | 
				
			||||||
                    continue
 | 
					                    continue
 | 
				
			||||||
                argparams.append(key)
 | 
					                argparams.append(key)
 | 
				
			||||||
    #elif scopenum == 3:
 | 
					    #elif scopenum == 3:
 | 
				
			||||||
    #    argparams = []
 | 
					    #    argparams = []
 | 
				
			||||||
    #    for argname, param in cs.params.items():
 | 
					    #    for argname, param in cs.indices.items():
 | 
				
			||||||
    #        if cs._arg2scopenum[argname] == scopenum:
 | 
					    #        if cs._arg2scopenum[argname] == scopenum:
 | 
				
			||||||
    #            key = (argname, param, getfslineno(item.obj))
 | 
					    #            key = (argname, param, getfslineno(item.obj))
 | 
				
			||||||
    #            if key in ignore:
 | 
					    #            if key in ignore:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -355,6 +355,35 @@ class TestFunction:
 | 
				
			||||||
        rec = testdir.inline_run()
 | 
					        rec = testdir.inline_run()
 | 
				
			||||||
        rec.assertoutcome(passed=2)
 | 
					        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):
 | 
					    def test_parametrize_with_mark(selfself, testdir):
 | 
				
			||||||
        items = testdir.getitems("""
 | 
					        items = testdir.getitems("""
 | 
				
			||||||
            import pytest
 | 
					            import pytest
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue