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.
This commit is contained in:
parent
f456e376b9
commit
bc42cf8ffb
|
@ -1,6 +1,6 @@
|
||||||
""" per-test stdout/stderr capturing mechanisms, ``capsys`` and ``capfd`` function arguments. """
|
""" per-test stdout/stderr capturing mechanisms, ``capsys`` and ``capfd`` function arguments. """
|
||||||
|
|
||||||
import py
|
import pytest, py
|
||||||
import os
|
import os
|
||||||
|
|
||||||
def pytest_addoption(parser):
|
def pytest_addoption(parser):
|
||||||
|
@ -143,13 +143,16 @@ class CaptureManager:
|
||||||
addouterr(rep, outerr)
|
addouterr(rep, outerr)
|
||||||
return rep
|
return rep
|
||||||
|
|
||||||
|
@pytest.mark.tryfirst
|
||||||
def pytest_runtest_setup(self, item):
|
def pytest_runtest_setup(self, item):
|
||||||
self.resumecapture_item(item)
|
self.resumecapture_item(item)
|
||||||
|
|
||||||
|
@pytest.mark.tryfirst
|
||||||
def pytest_runtest_call(self, item):
|
def pytest_runtest_call(self, item):
|
||||||
self.resumecapture_item(item)
|
self.resumecapture_item(item)
|
||||||
self.activate_funcargs(item)
|
self.activate_funcargs(item)
|
||||||
|
|
||||||
|
@pytest.mark.tryfirst
|
||||||
def pytest_runtest_teardown(self, item):
|
def pytest_runtest_teardown(self, item):
|
||||||
self.resumecapture_item(item)
|
self.resumecapture_item(item)
|
||||||
|
|
||||||
|
@ -168,6 +171,7 @@ class CaptureManager:
|
||||||
if hasattr(self, '_capturing'):
|
if hasattr(self, '_capturing'):
|
||||||
self.suspendcapture()
|
self.suspendcapture()
|
||||||
|
|
||||||
|
@pytest.mark.tryfirst
|
||||||
def pytest_runtest_makereport(self, __multicall__, item, call):
|
def pytest_runtest_makereport(self, __multicall__, item, call):
|
||||||
self.deactivate_funcargs()
|
self.deactivate_funcargs()
|
||||||
rep = __multicall__.execute()
|
rep = __multicall__.execute()
|
||||||
|
|
|
@ -12,7 +12,7 @@ assert py.__version__.split(".")[:2] >= ['2', '0'], ("installation problem: "
|
||||||
"%s is too old, remove or upgrade 'py'" % (py.__version__))
|
"%s is too old, remove or upgrade 'py'" % (py.__version__))
|
||||||
|
|
||||||
default_plugins = (
|
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 "
|
"tmpdir monkeypatch recwarn pastebin helpconfig nose assertion genscript "
|
||||||
"junitxml doctest").split()
|
"junitxml doctest").split()
|
||||||
|
|
||||||
|
@ -272,11 +272,19 @@ class PluginManager(object):
|
||||||
if plugins is None:
|
if plugins is None:
|
||||||
plugins = self._plugins
|
plugins = self._plugins
|
||||||
l = []
|
l = []
|
||||||
|
last = []
|
||||||
for plugin in plugins:
|
for plugin in plugins:
|
||||||
try:
|
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:
|
except AttributeError:
|
||||||
continue
|
continue
|
||||||
|
l.extend(last)
|
||||||
return l
|
return l
|
||||||
|
|
||||||
def call_plugin(self, plugin, methname, kwargs):
|
def call_plugin(self, plugin, methname, kwargs):
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
""" interactive debugging with PDB, the Python Debugger. """
|
""" interactive debugging with PDB, the Python Debugger. """
|
||||||
|
|
||||||
import py
|
import pytest, py
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
def pytest_addoption(parser):
|
def pytest_addoption(parser):
|
||||||
|
@ -45,9 +45,11 @@ class PdbInvoke:
|
||||||
def pytest_sessionfinish(self, session):
|
def pytest_sessionfinish(self, session):
|
||||||
# don't display failures again at the end
|
# don't display failures again at the end
|
||||||
session.config.option.tbstyle = "no"
|
session.config.option.tbstyle = "no"
|
||||||
|
|
||||||
|
@pytest.mark.tryfirst
|
||||||
def pytest_runtest_makereport(self, item, call, __multicall__):
|
def pytest_runtest_makereport(self, item, call, __multicall__):
|
||||||
if not call.excinfo or \
|
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):
|
call.excinfo.errisinstance(py.std.bdb.BdbQuit):
|
||||||
return
|
return
|
||||||
rep = __multicall__.execute()
|
rep = __multicall__.execute()
|
||||||
|
|
|
@ -19,8 +19,8 @@ def pytest_cmdline_main(config):
|
||||||
showfuncargs(config)
|
showfuncargs(config)
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
def pytest_namespace(__multicall__):
|
@pytest.mark.trylast
|
||||||
__multicall__.execute()
|
def pytest_namespace():
|
||||||
raises.Exception = pytest.fail.Exception
|
raises.Exception = pytest.fail.Exception
|
||||||
return {
|
return {
|
||||||
'raises' : raises,
|
'raises' : raises,
|
||||||
|
|
|
@ -5,7 +5,7 @@ see http://pytest.org for documentation and details
|
||||||
|
|
||||||
(c) Holger Krekel and others, 2004-2010
|
(c) Holger Krekel and others, 2004-2010
|
||||||
"""
|
"""
|
||||||
__version__ = '2.0.0.dev31'
|
__version__ = '2.0.0.dev32'
|
||||||
__all__ = ['main']
|
__all__ = ['main']
|
||||||
|
|
||||||
from _pytest.core import main, UsageError, _preloadplugins
|
from _pytest.core import main, UsageError, _preloadplugins
|
||||||
|
|
2
setup.py
2
setup.py
|
@ -22,7 +22,7 @@ def main():
|
||||||
name='pytest',
|
name='pytest',
|
||||||
description='py.test: simple powerful testing with Python',
|
description='py.test: simple powerful testing with Python',
|
||||||
long_description = long_description,
|
long_description = long_description,
|
||||||
version='2.0.0.dev31',
|
version='2.0.0.dev32',
|
||||||
url='http://pytest.org',
|
url='http://pytest.org',
|
||||||
license='MIT license',
|
license='MIT license',
|
||||||
platforms=['unix', 'linux', 'osx', 'cygwin', 'win32'],
|
platforms=['unix', 'linux', 'osx', 'cygwin', 'win32'],
|
||||||
|
|
|
@ -377,3 +377,13 @@ def test_fdfuncarg_skips_on_no_osdup(testdir):
|
||||||
result.stdout.fnmatch_lines([
|
result.stdout.fnmatch_lines([
|
||||||
"*1 skipped*"
|
"*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()
|
||||||
|
|
|
@ -418,6 +418,35 @@ class TestPytestPluginInteractions:
|
||||||
assert not pluginmanager.listattr("hello")
|
assert not pluginmanager.listattr("hello")
|
||||||
assert pluginmanager.listattr("x") == [42]
|
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):
|
def test_namespace_has_default_and_env_plugins(testdir):
|
||||||
p = testdir.makepyfile("""
|
p = testdir.makepyfile("""
|
||||||
import pytest
|
import pytest
|
||||||
|
|
Loading…
Reference in New Issue