introduce pluginmanager.ensure_teardown() which allows
This commit is contained in:
parent
ac19212b2d
commit
a930f44e60
|
@ -22,6 +22,13 @@ def pytest_cmdline_parse(pluginmanager, args):
|
||||||
method = "sys"
|
method = "sys"
|
||||||
capman = CaptureManager(method)
|
capman = CaptureManager(method)
|
||||||
pluginmanager.register(capman, "capturemanager")
|
pluginmanager.register(capman, "capturemanager")
|
||||||
|
# make sure that capturemanager is properly reset at final shutdown
|
||||||
|
def teardown():
|
||||||
|
try:
|
||||||
|
capman.reset_capturings()
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
|
pluginmanager.add_shutdown(teardown)
|
||||||
|
|
||||||
def addouterr(rep, outerr):
|
def addouterr(rep, outerr):
|
||||||
for secname, content in zip(["out", "err"], outerr):
|
for secname, content in zip(["out", "err"], outerr):
|
||||||
|
@ -82,6 +89,7 @@ class CaptureManager:
|
||||||
for name, cap in self._method2capture.items():
|
for name, cap in self._method2capture.items():
|
||||||
cap.reset()
|
cap.reset()
|
||||||
|
|
||||||
|
|
||||||
def resumecapture_item(self, item):
|
def resumecapture_item(self, item):
|
||||||
method = self._getmethod(item.config, item.fspath)
|
method = self._getmethod(item.config, item.fspath)
|
||||||
if not hasattr(item, 'outerr'):
|
if not hasattr(item, 'outerr'):
|
||||||
|
|
|
@ -80,6 +80,7 @@ class PluginManager(object):
|
||||||
self._hints = []
|
self._hints = []
|
||||||
self.trace = TagTracer().get("pluginmanage")
|
self.trace = TagTracer().get("pluginmanage")
|
||||||
self._plugin_distinfo = []
|
self._plugin_distinfo = []
|
||||||
|
self._shutdown = []
|
||||||
if os.environ.get('PYTEST_DEBUG'):
|
if os.environ.get('PYTEST_DEBUG'):
|
||||||
err = sys.stderr
|
err = sys.stderr
|
||||||
encoding = getattr(err, 'encoding', 'utf8')
|
encoding = getattr(err, 'encoding', 'utf8')
|
||||||
|
@ -118,6 +119,17 @@ class PluginManager(object):
|
||||||
if value == plugin:
|
if value == plugin:
|
||||||
del self._name2plugin[name]
|
del self._name2plugin[name]
|
||||||
|
|
||||||
|
def add_shutdown(self, func):
|
||||||
|
self._shutdown.append(func)
|
||||||
|
|
||||||
|
def ensure_shutdown(self):
|
||||||
|
while self._shutdown:
|
||||||
|
func = self._shutdown.pop()
|
||||||
|
func()
|
||||||
|
self._plugins = []
|
||||||
|
self._name2plugin.clear()
|
||||||
|
self._listattrcache.clear()
|
||||||
|
|
||||||
def isregistered(self, plugin, name=None):
|
def isregistered(self, plugin, name=None):
|
||||||
if self.getplugin(name) is not None:
|
if self.getplugin(name) is not None:
|
||||||
return True
|
return True
|
||||||
|
@ -286,7 +298,7 @@ class PluginManager(object):
|
||||||
config = self._config
|
config = self._config
|
||||||
del self._config
|
del self._config
|
||||||
config.hook.pytest_unconfigure(config=config)
|
config.hook.pytest_unconfigure(config=config)
|
||||||
config.pluginmanager.unregister(self)
|
config.pluginmanager.ensure_shutdown()
|
||||||
|
|
||||||
def notify_exception(self, excinfo, option=None):
|
def notify_exception(self, excinfo, option=None):
|
||||||
if option and option.fulltrace:
|
if option and option.fulltrace:
|
||||||
|
|
|
@ -106,6 +106,7 @@ def wrap_session(config, doit):
|
||||||
exitstatus=session.exitstatus)
|
exitstatus=session.exitstatus)
|
||||||
if initstate >= 1:
|
if initstate >= 1:
|
||||||
config.pluginmanager.do_unconfigure(config)
|
config.pluginmanager.do_unconfigure(config)
|
||||||
|
config.pluginmanager.ensure_shutdown()
|
||||||
return session.exitstatus
|
return session.exitstatus
|
||||||
|
|
||||||
def pytest_cmdline_main(config):
|
def pytest_cmdline_main(config):
|
||||||
|
|
|
@ -83,7 +83,8 @@ class HookRecorder:
|
||||||
|
|
||||||
def finish_recording(self):
|
def finish_recording(self):
|
||||||
for recorder in self._recorders.values():
|
for recorder in self._recorders.values():
|
||||||
self._pluginmanager.unregister(recorder)
|
if self._pluginmanager.isregistered(recorder):
|
||||||
|
self._pluginmanager.unregister(recorder)
|
||||||
self._recorders.clear()
|
self._recorders.clear()
|
||||||
|
|
||||||
def _makecallparser(self, method):
|
def _makecallparser(self, method):
|
||||||
|
@ -361,7 +362,7 @@ class TmpTestdir:
|
||||||
if not plugins:
|
if not plugins:
|
||||||
plugins = []
|
plugins = []
|
||||||
plugins.append(Collect())
|
plugins.append(Collect())
|
||||||
ret = self.pytestmain(list(args), plugins=plugins)
|
ret = pytest.main(list(args), plugins=plugins)
|
||||||
reprec = rec[0]
|
reprec = rec[0]
|
||||||
reprec.ret = ret
|
reprec.ret = ret
|
||||||
assert len(rec) == 1
|
assert len(rec) == 1
|
||||||
|
@ -376,14 +377,15 @@ class TmpTestdir:
|
||||||
args.append("--basetemp=%s" % self.tmpdir.dirpath('basetemp'))
|
args.append("--basetemp=%s" % self.tmpdir.dirpath('basetemp'))
|
||||||
import _pytest.core
|
import _pytest.core
|
||||||
config = _pytest.core._prepareconfig(args, self.plugins)
|
config = _pytest.core._prepareconfig(args, self.plugins)
|
||||||
# the in-process pytest invocation needs to avoid leaking FDs
|
# we don't know what the test will do with this half-setup config
|
||||||
# so we register a "reset_capturings" callmon the capturing manager
|
# object and thus we make sure it gets unconfigured properly in any
|
||||||
# and make sure it gets called
|
# case (otherwise capturing could still be active, for example)
|
||||||
config._cleanup.append(
|
def ensure_unconfigure():
|
||||||
config.pluginmanager.getplugin("capturemanager").reset_capturings)
|
if hasattr(config.pluginmanager, "_config"):
|
||||||
import _pytest.config
|
config.pluginmanager.do_unconfigure(config)
|
||||||
self.request.addfinalizer(
|
config.pluginmanager.ensure_shutdown()
|
||||||
lambda: _pytest.config.pytest_unconfigure(config))
|
|
||||||
|
self.request.addfinalizer(ensure_unconfigure)
|
||||||
return config
|
return config
|
||||||
|
|
||||||
def parseconfigure(self, *args):
|
def parseconfigure(self, *args):
|
||||||
|
@ -428,17 +430,6 @@ class TmpTestdir:
|
||||||
return py.std.subprocess.Popen(cmdargs,
|
return py.std.subprocess.Popen(cmdargs,
|
||||||
stdout=stdout, stderr=stderr, **kw)
|
stdout=stdout, stderr=stderr, **kw)
|
||||||
|
|
||||||
def pytestmain(self, *args, **kwargs):
|
|
||||||
class ResetCapturing:
|
|
||||||
@pytest.mark.trylast
|
|
||||||
def pytest_unconfigure(self, config):
|
|
||||||
capman = config.pluginmanager.getplugin("capturemanager")
|
|
||||||
capman.reset_capturings()
|
|
||||||
plugins = kwargs.setdefault("plugins", [])
|
|
||||||
rc = ResetCapturing()
|
|
||||||
plugins.append(rc)
|
|
||||||
return pytest.main(*args, **kwargs)
|
|
||||||
|
|
||||||
def run(self, *cmdargs):
|
def run(self, *cmdargs):
|
||||||
return self._run(*cmdargs)
|
return self._run(*cmdargs)
|
||||||
|
|
||||||
|
|
|
@ -391,15 +391,15 @@ class TestInvocationVariants:
|
||||||
def test_equivalence_pytest_pytest(self):
|
def test_equivalence_pytest_pytest(self):
|
||||||
assert pytest.main == py.test.cmdline.main
|
assert pytest.main == py.test.cmdline.main
|
||||||
|
|
||||||
def test_invoke_with_string(self, testdir, capsys):
|
def test_invoke_with_string(self, capsys):
|
||||||
retcode = testdir.pytestmain("-h")
|
retcode = pytest.main("-h")
|
||||||
assert not retcode
|
assert not retcode
|
||||||
out, err = capsys.readouterr()
|
out, err = capsys.readouterr()
|
||||||
assert "--help" in out
|
assert "--help" in out
|
||||||
pytest.raises(ValueError, lambda: pytest.main(0))
|
pytest.raises(ValueError, lambda: pytest.main(0))
|
||||||
|
|
||||||
def test_invoke_with_path(self, testdir, capsys):
|
def test_invoke_with_path(self, tmpdir, capsys):
|
||||||
retcode = testdir.pytestmain(testdir.tmpdir)
|
retcode = pytest.main(tmpdir)
|
||||||
assert not retcode
|
assert not retcode
|
||||||
out, err = capsys.readouterr()
|
out, err = capsys.readouterr()
|
||||||
|
|
||||||
|
@ -408,7 +408,7 @@ class TestInvocationVariants:
|
||||||
def pytest_addoption(self, parser):
|
def pytest_addoption(self, parser):
|
||||||
parser.addoption("--myopt")
|
parser.addoption("--myopt")
|
||||||
|
|
||||||
testdir.pytestmain(["-h"], plugins=[MyPlugin()])
|
pytest.main(["-h"], plugins=[MyPlugin()])
|
||||||
out, err = capsys.readouterr()
|
out, err = capsys.readouterr()
|
||||||
assert "--myopt" in out
|
assert "--myopt" in out
|
||||||
|
|
||||||
|
|
|
@ -123,7 +123,7 @@ class TestCollectPluginHookRelay:
|
||||||
def pytest_collect_file(self, path, parent):
|
def pytest_collect_file(self, path, parent):
|
||||||
wascalled.append(path)
|
wascalled.append(path)
|
||||||
testdir.makefile(".abc", "xyz")
|
testdir.makefile(".abc", "xyz")
|
||||||
testdir.pytestmain([testdir.tmpdir], plugins=[Plugin()])
|
pytest.main([testdir.tmpdir], plugins=[Plugin()])
|
||||||
assert len(wascalled) == 1
|
assert len(wascalled) == 1
|
||||||
assert wascalled[0].ext == '.abc'
|
assert wascalled[0].ext == '.abc'
|
||||||
|
|
||||||
|
@ -134,7 +134,7 @@ class TestCollectPluginHookRelay:
|
||||||
wascalled.append(path.basename)
|
wascalled.append(path.basename)
|
||||||
testdir.mkdir("hello")
|
testdir.mkdir("hello")
|
||||||
testdir.mkdir("world")
|
testdir.mkdir("world")
|
||||||
testdir.pytestmain(testdir.tmpdir, plugins=[Plugin()])
|
pytest.main(testdir.tmpdir, plugins=[Plugin()])
|
||||||
assert "hello" in wascalled
|
assert "hello" in wascalled
|
||||||
assert "world" in wascalled
|
assert "world" in wascalled
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@ import py, pytest
|
||||||
import pdb
|
import pdb
|
||||||
|
|
||||||
xfail_if_pdbpp_installed = pytest.mark.xfail(hasattr(pdb, "__author__"),
|
xfail_if_pdbpp_installed = pytest.mark.xfail(hasattr(pdb, "__author__"),
|
||||||
reason="doctest/pdbpp problem: https://bitbucket.org/antocuni/pdb/issue/24/doctests-fail-when-pdbpp-is-installed")
|
reason="doctest/pdbpp problem: https://bitbucket.org/antocuni/pdb/issue/24/doctests-fail-when-pdbpp-is-installed", run=False)
|
||||||
|
|
||||||
class TestDoctests:
|
class TestDoctests:
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue