1 new commit in pytest:

https://bitbucket.org/hpk42/pytest/commits/bd9f28f011ea/
Changeset:   bd9f28f011ea
Branch:      yield-test-run-inline
User:        RonnyPfannschmidt
Date:        2015-02-10 23:33:18+00:00
Summary:     addresses #16 - replace Generator with 
pytest_pyfunc_interpret_result
Affected #:  10 files

diff -r 46d5ac0ba396af887969a3cc9940fccba5ff1955 -r 
bd9f28f011eafe48ddf95b6a3e9dd260aa69c99f CHANGELOG
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,6 +1,16 @@
 2.7.0.dev (compared to 2.6.4)
 -----------------------------
 
+- introduce the hook pytest_pyfunc_interpret_result
+  this eases interpreting test functions results like generators,
+  twisted inline defereds, futures and asyncio generators
+
+- replace the Generator concept with the pytest_pyfunc_interpret_result hook
+  (Note: this change reduces reporting detail for generator tests,
+   that will be addressed in a later release)
+
+  the Generator class is now a alias to Function
+
 - add ability to set command line options by environment variable 
PYTEST_ADDOPTS.
 
 - fix issue655: work around different ways that cause python2/3

diff -r 46d5ac0ba396af887969a3cc9940fccba5ff1955 -r 
bd9f28f011eafe48ddf95b6a3e9dd260aa69c99f _pytest/hookspec.py
--- a/_pytest/hookspec.py
+++ b/_pytest/hookspec.py
@@ -136,6 +136,10 @@
     """ call underlying test function. """
 pytest_pyfunc_call.firstresult = True
 
+
+def pytest_pyfunc_interpret_result(pyfuncitem, result):
+    """ interpret the return value of the underlying test function. """
+
 def pytest_generate_tests(metafunc):
     """ generate (multiple) parametrized calls to a test function."""
 

diff -r 46d5ac0ba396af887969a3cc9940fccba5ff1955 -r 
bd9f28f011eafe48ddf95b6a3e9dd260aa69c99f _pytest/nose.py
--- a/_pytest/nose.py
+++ b/_pytest/nose.py
@@ -27,13 +27,6 @@
 @pytest.mark.trylast
 def pytest_runtest_setup(item):
     if is_potential_nosetest(item):
-        if isinstance(item.parent, pytest.Generator):
-            gen = item.parent
-            if not hasattr(gen, '_nosegensetup'):
-                call_optional(gen.obj, 'setup')
-                if isinstance(gen.parent, pytest.Instance):
-                    call_optional(gen.parent.obj, 'setup')
-                gen._nosegensetup = True
         if not call_optional(item.obj, 'setup'):
             # call module level setup if there is no object level one
             call_optional(item.parent.obj, 'setup')
@@ -49,11 +42,6 @@
         #    del item.parent._nosegensetup
 
 
-def pytest_make_collect_report(collector):
-    if isinstance(collector, pytest.Generator):
-        call_optional(collector.obj, 'setup')
-
-
 def is_potential_nosetest(item):
     # extra check needed since we do not do nose style setup/teardown
     # on direct unittest style classes

diff -r 46d5ac0ba396af887969a3cc9940fccba5ff1955 -r 
bd9f28f011eafe48ddf95b6a3e9dd260aa69c99f _pytest/python.py
--- a/_pytest/python.py
+++ b/_pytest/python.py
@@ -177,7 +177,9 @@
         'raises' : raises,
         'collect': {
         'Module': Module, 'Class': Class, 'Instance': Instance,
-        'Function': Function, 'Generator': Generator,
+        'Function': Function,
+        # TODO: backward compatibility check
+        'Generator': Function,
         '_fillfuncargs': fillfixtures}
     }
 
@@ -188,16 +190,38 @@
 
 
 @pytest.mark.trylast
+def pytest_pyfunc_interpret_result(pyfuncitem, result):
+    if inspect.isgenerator(result):
+        pyfuncitem.warn(
+            code='G01',
+            message='generator test, reporting is limited')
+        for check in result:
+            # TODO(ronny): subtest support needed
+            if callable(check):
+                check()
+            elif not isinstance(check, tuple):
+                pytest.fail('%r is not a check' % (check,))
+            elif callable(check[0]):
+                check[0](*check[1:])
+            elif callable(check[1]):
+                check[1](*check[2:])
+            else:
+                pytest.fail(
+                    'generator test check not callable \n%r' % (check,))
+
+
+@pytest.mark.trylast
 def pytest_pyfunc_call(pyfuncitem):
     testfunction = pyfuncitem.obj
-    if pyfuncitem._isyieldedfunction():
-        testfunction(*pyfuncitem._args)
-    else:
-        funcargs = pyfuncitem.funcargs
-        testargs = {}
-        for arg in pyfuncitem._fixtureinfo.argnames:
-            testargs[arg] = funcargs[arg]
-        testfunction(**testargs)
+    funcargs = pyfuncitem.funcargs
+    testargs = {}
+    for arg in pyfuncitem._fixtureinfo.argnames:
+        testargs[arg] = funcargs[arg]
+    result = testfunction(**testargs)
+    if result is not None:
+        pyfuncitem.ihook.pytest_pyfunc_interpret_result(
+            pyfuncitem=pyfuncitem,
+            result=result)
     return True
 
 def pytest_collect_file(path, parent):
@@ -235,10 +259,7 @@
                 "cannot collect %r because it is not a function."
                 % name, )
         if getattr(obj, "__test__", True):
-            if is_generator(obj):
-                res = Generator(name, parent=collector)
-            else:
-                res = list(collector._genfunctions(name, obj))
+            res = list(collector._genfunctions(name, obj))
             outcome.force_result(res)
 
 def is_generator(func):
@@ -621,43 +642,6 @@
         return self._repr_failure_py(excinfo, style=style)
 
 
-class Generator(FunctionMixin, PyCollector):
-    def collect(self):
-        # test generators are seen as collectors but they also
-        # invoke setup/teardown on popular request
-        # (induced by the common "test_*" naming shared with normal tests)
-        self.session._setupstate.prepare(self)
-        # see FunctionMixin.setup and test_setupstate_is_preserved_134
-        self._preservedparent = self.parent.obj
-        l = []
-        seen = {}
-        for i, x in enumerate(self.obj()):
-            name, call, args = self.getcallargs(x)
-            if not callable(call):
-                raise TypeError("%r yielded non callable test %r" %(self.obj, 
call,))
-            if name is None:
-                name = "[%d]" % i
-            else:
-                name = "['%s']" % name
-            if name in seen:
-                raise ValueError("%r generated tests with non-unique name %r" 
%(self, name))
-            seen[name] = True
-            l.append(self.Function(name, self, args=args, callobj=call))
-        return l
-
-    def getcallargs(self, obj):
-        if not isinstance(obj, (tuple, list)):
-            obj = (obj,)
-        # explict naming
-        if isinstance(obj[0], py.builtin._basestring):
-            name = obj[0]
-            obj = obj[1:]
-        else:
-            name = None
-        call, args = obj[0], obj[1:]
-        return name, call, args
-
-
 def hasinit(obj):
     init = getattr(obj, '__init__', None)
     if init:

diff -r 46d5ac0ba396af887969a3cc9940fccba5ff1955 -r 
bd9f28f011eafe48ddf95b6a3e9dd260aa69c99f testing/python/collect.py
--- a/testing/python/collect.py
+++ b/testing/python/collect.py
@@ -76,199 +76,6 @@
         ])
 
 
-class TestGenerator:
-    def test_generative_functions(self, testdir):
-        modcol = testdir.getmodulecol("""
-            def func1(arg, arg2):
-                assert arg == arg2
-
-            def test_gen():
-                yield func1, 17, 3*5
-                yield func1, 42, 6*7
-        """)
-        colitems = modcol.collect()
-        assert len(colitems) == 1
-        gencol = colitems[0]
-        assert isinstance(gencol, pytest.Generator)
-        gencolitems = gencol.collect()
-        assert len(gencolitems) == 2
-        assert isinstance(gencolitems[0], pytest.Function)
-        assert isinstance(gencolitems[1], pytest.Function)
-        assert gencolitems[0].name == '[0]'
-        assert gencolitems[0].obj.__name__ == 'func1'
-
-    def test_generative_methods(self, testdir):
-        modcol = testdir.getmodulecol("""
-            def func1(arg, arg2):
-                assert arg == arg2
-            class TestGenMethods:
-                def test_gen(self):
-                    yield func1, 17, 3*5
-                    yield func1, 42, 6*7
-        """)
-        gencol = modcol.collect()[0].collect()[0].collect()[0]
-        assert isinstance(gencol, pytest.Generator)
-        gencolitems = gencol.collect()
-        assert len(gencolitems) == 2
-        assert isinstance(gencolitems[0], pytest.Function)
-        assert isinstance(gencolitems[1], pytest.Function)
-        assert gencolitems[0].name == '[0]'
-        assert gencolitems[0].obj.__name__ == 'func1'
-
-    def test_generative_functions_with_explicit_names(self, testdir):
-        modcol = testdir.getmodulecol("""
-            def func1(arg, arg2):
-                assert arg == arg2
-
-            def test_gen():
-                yield "seventeen", func1, 17, 3*5
-                yield "fortytwo", func1, 42, 6*7
-        """)
-        colitems = modcol.collect()
-        assert len(colitems) == 1
-        gencol = colitems[0]
-        assert isinstance(gencol, pytest.Generator)
-        gencolitems = gencol.collect()
-        assert len(gencolitems) == 2
-        assert isinstance(gencolitems[0], pytest.Function)
-        assert isinstance(gencolitems[1], pytest.Function)
-        assert gencolitems[0].name == "['seventeen']"
-        assert gencolitems[0].obj.__name__ == 'func1'
-        assert gencolitems[1].name == "['fortytwo']"
-        assert gencolitems[1].obj.__name__ == 'func1'
-
-    def test_generative_functions_unique_explicit_names(self, testdir):
-        # generative
-        modcol = testdir.getmodulecol("""
-            def func(): pass
-            def test_gen():
-                yield "name", func
-                yield "name", func
-        """)
-        colitems = modcol.collect()
-        assert len(colitems) == 1
-        gencol = colitems[0]
-        assert isinstance(gencol, pytest.Generator)
-        pytest.raises(ValueError, "gencol.collect()")
-
-    def test_generative_methods_with_explicit_names(self, testdir):
-        modcol = testdir.getmodulecol("""
-            def func1(arg, arg2):
-                assert arg == arg2
-            class TestGenMethods:
-                def test_gen(self):
-                    yield "m1", func1, 17, 3*5
-                    yield "m2", func1, 42, 6*7
-        """)
-        gencol = modcol.collect()[0].collect()[0].collect()[0]
-        assert isinstance(gencol, pytest.Generator)
-        gencolitems = gencol.collect()
-        assert len(gencolitems) == 2
-        assert isinstance(gencolitems[0], pytest.Function)
-        assert isinstance(gencolitems[1], pytest.Function)
-        assert gencolitems[0].name == "['m1']"
-        assert gencolitems[0].obj.__name__ == 'func1'
-        assert gencolitems[1].name == "['m2']"
-        assert gencolitems[1].obj.__name__ == 'func1'
-
-    def test_order_of_execution_generator_same_codeline(self, testdir, tmpdir):
-        o = testdir.makepyfile("""
-            def test_generative_order_of_execution():
-                import py, pytest
-                test_list = []
-                expected_list = list(range(6))
-
-                def list_append(item):
-                    test_list.append(item)
-
-                def assert_order_of_execution():
-                    py.builtin.print_('expected order', expected_list)
-                    py.builtin.print_('but got       ', test_list)
-                    assert test_list == expected_list
-
-                for i in expected_list:
-                    yield list_append, i
-                yield assert_order_of_execution
-        """)
-        reprec = testdir.inline_run(o)
-        passed, skipped, failed = reprec.countoutcomes()
-        assert passed == 7
-        assert not skipped and not failed
-
-    def test_order_of_execution_generator_different_codeline(self, testdir):
-        o = testdir.makepyfile("""
-            def test_generative_tests_different_codeline():
-                import py, pytest
-                test_list = []
-                expected_list = list(range(3))
-
-                def list_append_2():
-                    test_list.append(2)
-
-                def list_append_1():
-                    test_list.append(1)
-
-                def list_append_0():
-                    test_list.append(0)
-
-                def assert_order_of_execution():
-                    py.builtin.print_('expected order', expected_list)
-                    py.builtin.print_('but got       ', test_list)
-                    assert test_list == expected_list
-
-                yield list_append_0
-                yield list_append_1
-                yield list_append_2
-                yield assert_order_of_execution
-        """)
-        reprec = testdir.inline_run(o)
-        passed, skipped, failed = reprec.countoutcomes()
-        assert passed == 4
-        assert not skipped and not failed
-
-    def test_setupstate_is_preserved_134(self, testdir):
-        # yield-based tests are messy wrt to setupstate because
-        # during collection they already invoke setup functions
-        # and then again when they are run.  For now, we want to make sure
-        # that the old 1.3.4 behaviour is preserved such that all
-        # yielded functions all share the same "self" instance that
-        # has been used during collection.
-        o = testdir.makepyfile("""
-            setuplist = []
-            class TestClass:
-                def setup_method(self, func):
-                    #print "setup_method", self, func
-                    setuplist.append(self)
-                    self.init = 42
-
-                def teardown_method(self, func):
-                    self.init = None
-
-                def test_func1(self):
-                    pass
-
-                def test_func2(self):
-                    yield self.func2
-                    yield self.func2
-
-                def func2(self):
-                    assert self.init
-
-            def test_setuplist():
-                # once for test_func2 during collection
-                # once for test_func1 during test run
-                # once for test_func2 during test run
-                #print setuplist
-                assert len(setuplist) == 3, len(setuplist)
-                assert setuplist[0] == setuplist[2], setuplist
-                assert setuplist[1] != setuplist[2], setuplist
-        """)
-        reprec = testdir.inline_run(o, '-v')
-        passed, skipped, failed = reprec.countoutcomes()
-        assert passed == 4
-        assert not skipped and not failed
-
-
 class TestFunction:
     def test_getmodulecollector(self, testdir):
         item = testdir.getitem("def test_func(): pass")
@@ -690,37 +497,6 @@
         assert lineno == 1
         assert msg == "TestClass"
 
-    def test_generator_reportinfo(self, testdir):
-        modcol = testdir.getmodulecol("""
-            # lineno 0
-            def test_gen():
-                def check(x):
-                    assert x
-                yield check, 3
-        """)
-        gencol = testdir.collect_by_name(modcol, "test_gen")
-        fspath, lineno, modpath = gencol.reportinfo()
-        assert fspath == modcol.fspath
-        assert lineno == 1
-        assert modpath == "test_gen"
-
-        genitem = gencol.collect()[0]
-        fspath, lineno, modpath = genitem.reportinfo()
-        assert fspath == modcol.fspath
-        assert lineno == 2
-        assert modpath == "test_gen[0]"
-        """
-            def test_func():
-                pass
-            def test_genfunc():
-                def check(x):
-                    pass
-                yield check, 3
-            class TestClass:
-                def test_method(self):
-                    pass
-       """
-
 
 def test_customized_python_discovery(testdir):
     testdir.makeini("""

diff -r 46d5ac0ba396af887969a3cc9940fccba5ff1955 -r 
bd9f28f011eafe48ddf95b6a3e9dd260aa69c99f testing/python/fixture.py
--- a/testing/python/fixture.py
+++ b/testing/python/fixture.py
@@ -1246,9 +1246,7 @@
                 yield f, -3
         """)
         reprec = testdir.inline_run()
-        reprec.assertoutcome(passed=2)
-
-
+        reprec.assertoutcome(passed=1)
 
     def test_funcarg_and_setup(self, testdir):
         testdir.makepyfile("""

diff -r 46d5ac0ba396af887969a3cc9940fccba5ff1955 -r 
bd9f28f011eafe48ddf95b6a3e9dd260aa69c99f testing/test_nose.py
--- a/testing/test_nose.py
+++ b/testing/test_nose.py
@@ -146,6 +146,7 @@
     ])
 
 
+@pytest.mark.xfail(reason='generator tests dont hook into setup/teardown')
 def test_nose_test_generator_fixtures(testdir):
     p = testdir.makepyfile("""
         # taken from nose-0.11.1 unit_tests/test_generator_fixtures.py

diff -r 46d5ac0ba396af887969a3cc9940fccba5ff1955 -r 
bd9f28f011eafe48ddf95b6a3e9dd260aa69c99f testing/test_runner_xunit.py
--- a/testing/test_runner_xunit.py
+++ b/testing/test_runner_xunit.py
@@ -1,6 +1,7 @@
 #
 # test correct setup/teardowns at
 # module, class, and instance level
+import pytest
 
 def test_module_and_function_setup(testdir):
     reprec = testdir.inline_runsource("""
@@ -141,6 +142,8 @@
     """)
     reprec.assertoutcome(failed=1, passed=1)
 
+
+@pytest.mark.xfail(reason='generator check reporting detail got reduced')
 def test_method_generator_setup(testdir):
     reprec = testdir.inline_runsource("""
         class TestSetupTeardownOnInstance:

diff -r 46d5ac0ba396af887969a3cc9940fccba5ff1955 -r 
bd9f28f011eafe48ddf95b6a3e9dd260aa69c99f testing/test_session.py
--- a/testing/test_session.py
+++ b/testing/test_session.py
@@ -61,9 +61,10 @@
             def test_1():
                 yield None
         """)
-        failures = reprec.getfailedcollections()
-        out = failures[0].longrepr.reprcrash.message
-        i = out.find('TypeError')
+        passed, skipped, failed = reprec.listoutcomes()
+        assert len(failed) == 1
+        out = failed[0].longrepr.reprcrash.message
+        i = out.find('not a check')
         assert i != -1
 
     def test_syntax_error_module(self, testdir):

diff -r 46d5ac0ba396af887969a3cc9940fccba5ff1955 -r 
bd9f28f011eafe48ddf95b6a3e9dd260aa69c99f testing/test_terminal.py
--- a/testing/test_terminal.py
+++ b/testing/test_terminal.py
@@ -453,7 +453,7 @@
             "*test_verbose_reporting.py::test_fail *FAIL*",
             "*test_verbose_reporting.py::test_pass *PASS*",
             "*test_verbose_reporting.py::TestClass::test_skip *SKIP*",
-            "*test_verbose_reporting.py::test_gen*0* *FAIL*",
+            "*test_verbose_reporting.py::test_gen *FAIL*",
         ])
         assert result.ret == 1

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