1 new commit in pytest:
https://bitbucket.org/hpk42/pytest/commits/2d6050084698/
Changeset: 2d6050084698
User: hpk42
Date: 2013-12-07 20:55:17
Summary: fix issue396 -- properly sort tests using class-scoped
parametrization
also refix issue323 in a better way to avoid recursion for the fixture-grouping
algorithm alltogether.
Affected #: 4 files
diff -r 2c3cb44dc7349346c87353ced3c5dc4add769803 -r
2d60500846988334a64c2abe6f80ac44a0ea0085 CHANGELOG
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -10,6 +10,15 @@
hook and expecting certain fixture instances are torn down within (very
unlikely and would have been unreliable anyway).
+- fix issue396 - correctly sort and finalize class-scoped parametrized
+ tests independently from number of methods on the class.
+
+- refix issue323 in a better way -- parametrization should now never
+ cause Runtime Recursion errors because the underlying algorithm
+ for re-ordering tests per-scope/per-fixture is not recursive
+ anymore (it was tail-call recursive before which could lead
+ to problems for more than >966 non-function scoped parameters).
+
- fix issue290 - there is preliminary support now for parametrizing
with repeated same values (sometimes useful to to test if calling
a second time works as with the first time).
diff -r 2c3cb44dc7349346c87353ced3c5dc4add769803 -r
2d60500846988334a64c2abe6f80ac44a0ea0085 _pytest/python.py
--- a/_pytest/python.py
+++ b/_pytest/python.py
@@ -1826,41 +1826,45 @@
# setups and teardowns
def reorder_items(items, ignore, cache, scopenum):
- if scopenum >= scopenum_function:
+ if scopenum >= scopenum_function or len(items) < 3:
return items
- if len(items) < 2:
- return items
- #print "\nparametrize_Sorted", items, ignore, cache, scopenum
+ items_done = []
+ while 1:
+ items_before, items_same, items_other, newignore = \
+ slice_items(items, ignore, cache, scopenum)
+ items_before = reorder_items(items_before, ignore, cache, scopenum+1)
+ if items_same is None:
+ # nothing to reorder in this scope
+ assert items_other is None
+ return items_done + items_before
+ items_done.extend(items_before)
+ items = items_same + items_other
+ ignore = newignore
+
+def slice_items(items, ignore, cache, scopenum):
# we pick the first item which uses a fixture instance in the requested
scope
# and which we haven't seen yet. We slice the input items list into
- # a list of items_nomatch, items_using_same_fixtureinstance and
- # items_remaining
+ # a list of items_nomatch, items_same and items_other
slicing_argkey = None
for i, item in enumerate(items):
argkeys = get_parametrized_fixture_keys(item, ignore, scopenum, cache)
if slicing_argkey is None:
if argkeys:
slicing_argkey = argkeys.pop()
- items_using_same_fixtureinstance = [item]
- items_nomatch = items[:i]
- items_remaining = []
+ items_before = items[:i]
+ items_same = [item]
+ items_other = []
continue
if slicing_argkey in argkeys:
- items_using_same_fixtureinstance.append(item)
+ items_same.append(item)
else:
- items_remaining.append(item)
-
- if slicing_argkey is None or len(items_using_same_fixtureinstance) == 1:
- # nothing to sort on this level
- return reorder_items(items, ignore, cache, scopenum+1)
-
- items_nomatch = reorder_items(items_nomatch, ignore, cache, scopenum+1)
+ items_other.append(item)
+ if slicing_argkey is None:
+ return items, None, None, None
newignore = ignore.copy()
newignore.add(slicing_argkey)
- part2 = reorder_items(items_using_same_fixtureinstance + items_remaining,
- newignore, cache, scopenum)
- return items_nomatch + part2
+ return (items_before, items_same, items_other, newignore)
def get_parametrized_fixture_keys(item, ignore, scopenum, cache):
""" return list of keys for all parametrized arguments which match
@@ -1882,13 +1886,14 @@
elif scopenum == 1: # module
key = (argname, param_index, item.fspath)
elif scopenum == 2: # class
+ # enumerate classes per fspath
l = cache.setdefault(item.fspath, [])
try:
- i = l.index(item.cls)
+ numclass = l.index(item.cls)
except ValueError:
- i = len(l)
+ numclass = len(l)
l.append(item.cls)
- key = (argname, param_index, item.fspath, i)
+ key = (argname, param_index, item.fspath, item.cls)
if key not in ignore:
keys.add(key)
return keys
diff -r 2c3cb44dc7349346c87353ced3c5dc4add769803 -r
2d60500846988334a64c2abe6f80ac44a0ea0085 testing/python/fixture.py
--- a/testing/python/fixture.py
+++ b/testing/python/fixture.py
@@ -1889,6 +1889,34 @@
reprec = testdir.inline_run("-lvs")
reprec.assertoutcome(passed=3)
+ @pytest.mark.issue396
+ def test_class_scope_parametrization_ordering(self, testdir):
+ testdir.makepyfile("""
+ import pytest
+ l = []
+ @pytest.fixture(params=["John", "Doe"], scope="class")
+ def human(request):
+ request.addfinalizer(lambda: l.append("fin %s" %
request.param))
+ return request.param
+
+ class TestGreetings:
+ def test_hello(self, human):
+ l.append("test_hello")
+
+ class TestMetrics:
+ def test_name(self, human):
+ l.append("test_name")
+
+ def test_population(self, human):
+ l.append("test_population")
+ """)
+ reprec = testdir.inline_run()
+ reprec.assertoutcome(passed=6)
+ l = reprec.getcalls("pytest_runtest_call")[0].item.module.l
+ assert l == ["test_hello", "fin John", "test_hello", "fin Doe",
+ "test_name", "test_population", "fin John",
+ "test_name", "test_population", "fin Doe"]
+
def test_parametrize_setup_function(self, testdir):
testdir.makepyfile("""
import pytest
diff -r 2c3cb44dc7349346c87353ced3c5dc4add769803 -r
2d60500846988334a64c2abe6f80ac44a0ea0085 testing/python/metafunc.py
--- a/testing/python/metafunc.py
+++ b/testing/python/metafunc.py
@@ -592,6 +592,8 @@
def test_it(foo):
pass
+ def test_it2(foo):
+ pass
""")
reprec = testdir.inline_run("--collect-only")
assert not reprec.getcalls("pytest_internalerror")
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.
_______________________________________________
pytest-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pytest-commit