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
pytest-commit@python.org
https://mail.python.org/mailman/listinfo/pytest-commit

Reply via email to