[py-svn] pytest commit ce993aec28cc: add a way to mark hooks as "tryfirst" or "trylast" to influence its position in a hook chain.

commits-noreply at bitbucket.org commits-noreply at bitbucket.org
Mon Nov 22 12:06:38 CET 2010


# HG changeset patch -- Bitbucket.org
# Project pytest
# URL http://bitbucket.org/hpk42/pytest/overview
# User holger krekel <holger at merlinux.eu>
# Date 1290377879 -3600
# Node ID ce993aec28cc55b8edb513b4390397ff4508b1a2
# Parent  53915e1ea00656d7685dc2a500b61b3fae350e41
add a way to mark hooks as "tryfirst" or "trylast" to influence its position in a hook chain.
Use 'tryfirst' for capturing hooks so they can start capturing as early as possible,
including when conftests add output in runtest_setup hooks.

--- a/testing/test_capture.py
+++ b/testing/test_capture.py
@@ -377,3 +377,13 @@ def test_fdfuncarg_skips_on_no_osdup(tes
     result.stdout.fnmatch_lines([
         "*1 skipped*"
     ])
+
+def test_capture_conftest_runtest_setup(testdir):
+    testdir.makeconftest("""
+        def pytest_runtest_setup():
+            print ("hello19")
+    """)
+    testdir.makepyfile("def test_func(): pass")
+    result = testdir.runpytest()
+    assert result.ret == 0
+    assert 'hello19' not in result.stdout.str()

--- a/_pytest/python.py
+++ b/_pytest/python.py
@@ -19,8 +19,8 @@ def pytest_cmdline_main(config):
         showfuncargs(config)
         return 0
 
-def pytest_namespace(__multicall__):
-    __multicall__.execute()
+ at pytest.mark.trylast
+def pytest_namespace():
     raises.Exception = pytest.fail.Exception
     return {
         'raises' : raises,

--- a/_pytest/capture.py
+++ b/_pytest/capture.py
@@ -1,6 +1,6 @@
 """ per-test stdout/stderr capturing mechanisms, ``capsys`` and ``capfd`` function arguments.  """
 
-import py
+import pytest, py
 import os
 
 def pytest_addoption(parser):
@@ -143,13 +143,16 @@ class CaptureManager:
         addouterr(rep, outerr)
         return rep
 
+    @pytest.mark.tryfirst
     def pytest_runtest_setup(self, item):
         self.resumecapture_item(item)
 
+    @pytest.mark.tryfirst
     def pytest_runtest_call(self, item):
         self.resumecapture_item(item)
         self.activate_funcargs(item)
 
+    @pytest.mark.tryfirst
     def pytest_runtest_teardown(self, item):
         self.resumecapture_item(item)
 
@@ -168,6 +171,7 @@ class CaptureManager:
         if hasattr(self, '_capturing'):
             self.suspendcapture()
 
+    @pytest.mark.tryfirst
     def pytest_runtest_makereport(self, __multicall__, item, call):
         self.deactivate_funcargs()
         rep = __multicall__.execute()

--- a/_pytest/core.py
+++ b/_pytest/core.py
@@ -12,7 +12,7 @@ assert py.__version__.split(".")[:2] >= 
     "%s is too old, remove or upgrade 'py'" % (py.__version__))
 
 default_plugins = (
- "config session terminal runner python pdb capture unittest mark skipping "
+ "config mark session terminal runner python pdb unittest capture skipping "
  "tmpdir monkeypatch recwarn pastebin helpconfig nose assertion genscript "
  "junitxml doctest").split()
 
@@ -272,11 +272,19 @@ class PluginManager(object):
         if plugins is None:
             plugins = self._plugins
         l = []
+        last = []
         for plugin in plugins:
             try:
-                l.append(getattr(plugin, attrname))
+                meth = getattr(plugin, attrname)
+                if hasattr(meth, 'tryfirst'):
+                    last.append(meth)
+                elif hasattr(meth, 'trylast'):
+                    l.insert(0, meth)
+                else:
+                    l.append(meth)
             except AttributeError:
                 continue
+        l.extend(last)
         return l
 
     def call_plugin(self, plugin, methname, kwargs):

--- a/testing/test_core.py
+++ b/testing/test_core.py
@@ -418,6 +418,35 @@ class TestPytestPluginInteractions:
         assert not pluginmanager.listattr("hello")
         assert pluginmanager.listattr("x") == [42]
 
+    def test_listattr_tryfirst(self):
+        class P1:
+            @pytest.mark.tryfirst
+            def m(self):
+                return 17
+
+        class P2:
+            def m(self):
+                return 23
+        class P3:
+            def m(self):
+                return 19
+
+        pluginmanager = PluginManager()
+        p1 = P1()
+        p2 = P2()
+        p3 = P3()
+        pluginmanager.register(p1)
+        pluginmanager.register(p2)
+        pluginmanager.register(p3)
+        methods = pluginmanager.listattr('m')
+        assert methods == [p2.m, p3.m, p1.m]
+        del P1.m.__dict__['tryfirst']
+
+        pytest.mark.trylast(getattr(P2.m, 'im_func', P2.m))
+        methods = pluginmanager.listattr('m')
+        assert methods == [p2.m, p1.m, p3.m]
+
+
 def test_namespace_has_default_and_env_plugins(testdir):
     p = testdir.makepyfile("""
         import pytest

--- a/pytest.py
+++ b/pytest.py
@@ -5,7 +5,7 @@ see http://pytest.org for documentation 
 
 (c) Holger Krekel and others, 2004-2010
 """
-__version__ = '2.0.0.dev31'
+__version__ = '2.0.0.dev32'
 __all__ = ['main']
 
 from _pytest.core import main, UsageError, _preloadplugins

--- a/setup.py
+++ b/setup.py
@@ -22,7 +22,7 @@ def main():
         name='pytest',
         description='py.test: simple powerful testing with Python',
         long_description = long_description,
-        version='2.0.0.dev31',
+        version='2.0.0.dev32',
         url='http://pytest.org',
         license='MIT license',
         platforms=['unix', 'linux', 'osx', 'cygwin', 'win32'],

--- a/_pytest/pdb.py
+++ b/_pytest/pdb.py
@@ -1,6 +1,6 @@
 """ interactive debugging with PDB, the Python Debugger. """
 
-import py
+import pytest, py
 import sys
 
 def pytest_addoption(parser):
@@ -45,9 +45,11 @@ class PdbInvoke:
     def pytest_sessionfinish(self, session):
         # don't display failures again at the end
         session.config.option.tbstyle = "no"
+
+    @pytest.mark.tryfirst
     def pytest_runtest_makereport(self, item, call, __multicall__):
         if not call.excinfo or \
-            call.excinfo.errisinstance(py.test.skip.Exception) or \
+            call.excinfo.errisinstance(pytest.skip.Exception) or \
             call.excinfo.errisinstance(py.std.bdb.BdbQuit):
             return
         rep = __multicall__.execute()



More information about the pytest-commit mailing list