- turn on capturing before early conftest loading and make terminal writer

use the original stream.

- avoid resetting capture FDs/sys.stdout for each test by keeping capturing
  always turned on and looking at snapshotted capturing data during runtest
  and collection phases.
This commit is contained in:
holger krekel 2014-03-14 12:49:36 +01:00
parent f43cda9681
commit 9777703e03
11 changed files with 181 additions and 122 deletions

View File

@ -1,12 +1,11 @@
""" """
per-test stdout/stderr capturing mechanisms, per-test stdout/stderr capturing mechanism.
``capsys`` and ``capfd`` function arguments.
""" """
# note: py.io capture was where copied from
# pylib 1.4.20.dev2 (rev 13d9af95547e)
import sys import sys
import os import os
import tempfile import tempfile
import contextlib
import py import py
import pytest import pytest
@ -58,8 +57,18 @@ def pytest_load_initial_conftests(early_config, parser, args, __multicall__):
method = "fd" method = "fd"
if method == "fd" and not hasattr(os, "dup"): if method == "fd" and not hasattr(os, "dup"):
method = "sys" method = "sys"
pluginmanager = early_config.pluginmanager
if method != "no":
try:
sys.stdout.fileno()
except Exception:
dupped_stdout = sys.stdout
else:
dupped_stdout = dupfile(sys.stdout, buffering=1)
pluginmanager.register(dupped_stdout, "dupped_stdout")
#pluginmanager.add_shutdown(dupped_stdout.close)
capman = CaptureManager(method) capman = CaptureManager(method)
early_config.pluginmanager.register(capman, "capturemanager") pluginmanager.register(capman, "capturemanager")
# make sure that capturemanager is properly reset at final shutdown # make sure that capturemanager is properly reset at final shutdown
def teardown(): def teardown():
@ -68,13 +77,13 @@ def pytest_load_initial_conftests(early_config, parser, args, __multicall__):
except ValueError: except ValueError:
pass pass
early_config.pluginmanager.add_shutdown(teardown) pluginmanager.add_shutdown(teardown)
# make sure logging does not raise exceptions at the end # make sure logging does not raise exceptions at the end
def silence_logging_at_shutdown(): def silence_logging_at_shutdown():
if "logging" in sys.modules: if "logging" in sys.modules:
sys.modules["logging"].raiseExceptions = False sys.modules["logging"].raiseExceptions = False
early_config.pluginmanager.add_shutdown(silence_logging_at_shutdown) pluginmanager.add_shutdown(silence_logging_at_shutdown)
# finally trigger conftest loading but while capturing (issue93) # finally trigger conftest loading but while capturing (issue93)
capman.resumecapture() capman.resumecapture()
@ -89,23 +98,20 @@ def pytest_load_initial_conftests(early_config, parser, args, __multicall__):
raise raise
def addouterr(rep, outerr):
for secname, content in zip(["out", "err"], outerr):
if content:
rep.sections.append(("Captured std%s" % secname, content))
class NoCapture: class NoCapture:
def startall(self): def start_capturing(self):
pass pass
def resume(self): def stop_capturing(self):
pass
def pop_outerr_to_orig(self):
pass pass
def reset(self): def reset(self):
pass pass
def suspend(self): def readouterr(self):
return "", "" return "", ""
@ -147,7 +153,9 @@ class CaptureManager:
def reset_capturings(self): def reset_capturings(self):
for cap in self._method2capture.values(): for cap in self._method2capture.values():
cap.pop_outerr_to_orig()
cap.reset() cap.reset()
self._method2capture.clear()
def resumecapture_item(self, item): def resumecapture_item(self, item):
method = self._getmethod(item.config, item.fspath) method = self._getmethod(item.config, item.fspath)
@ -164,9 +172,9 @@ class CaptureManager:
self._capturing = method self._capturing = method
if cap is None: if cap is None:
self._method2capture[method] = cap = self._getcapture(method) self._method2capture[method] = cap = self._getcapture(method)
cap.startall() cap.start_capturing()
else: else:
cap.resume() cap.pop_outerr_to_orig()
def suspendcapture(self, item=None): def suspendcapture(self, item=None):
self.deactivate_funcargs() self.deactivate_funcargs()
@ -175,7 +183,7 @@ class CaptureManager:
del self._capturing del self._capturing
cap = self._method2capture.get(method) cap = self._method2capture.get(method)
if cap is not None: if cap is not None:
return cap.suspend() return cap.readouterr()
return "", "" return "", ""
def activate_funcargs(self, pyfuncitem): def activate_funcargs(self, pyfuncitem):
@ -194,47 +202,68 @@ class CaptureManager:
del self._capturing_funcarg del self._capturing_funcarg
return outerr return outerr
@pytest.mark.hookwrapper
def pytest_make_collect_report(self, __multicall__, collector): def pytest_make_collect_report(self, __multicall__, collector):
method = self._getmethod(collector.config, collector.fspath) method = self._getmethod(collector.config, collector.fspath)
try: try:
self.resumecapture(method) self.resumecapture(method)
except ValueError: except ValueError:
yield
# recursive collect, XXX refactor capturing # recursive collect, XXX refactor capturing
# to allow for more lightweight recursive capturing # to allow for more lightweight recursive capturing
return return
try: yield
rep = __multicall__.execute() out, err = self.suspendcapture()
finally: # XXX getting the report from the ongoing hook call is a bit
outerr = self.suspendcapture() # of a hack. We need to think about capturing during collection
addouterr(rep, outerr) # and find out if it's really needed fine-grained (per
return rep # collector).
if __multicall__.results:
rep = __multicall__.results[0]
if out:
rep.sections.append(("Captured stdout", out))
if err:
rep.sections.append(("Captured stderr", err))
@pytest.mark.tryfirst @pytest.mark.hookwrapper
def pytest_runtest_setup(self, item): def pytest_runtest_setup(self, item):
self.resumecapture_item(item) with self.item_capture_wrapper(item, "setup"):
yield
@pytest.mark.tryfirst @pytest.mark.hookwrapper
def pytest_runtest_call(self, item): def pytest_runtest_call(self, item):
self.resumecapture_item(item) with self.item_capture_wrapper(item, "call"):
self.activate_funcargs(item) yield
@pytest.mark.tryfirst @pytest.mark.hookwrapper
def pytest_runtest_teardown(self, item): def pytest_runtest_teardown(self, item):
self.resumecapture_item(item) with self.item_capture_wrapper(item, "teardown"):
yield
def pytest_keyboard_interrupt(self, excinfo):
if hasattr(self, '_capturing'):
self.suspendcapture()
@pytest.mark.tryfirst @pytest.mark.tryfirst
def pytest_runtest_makereport(self, item, call): def pytest_keyboard_interrupt(self, excinfo):
funcarg_outerr = self.deactivate_funcargs() self.reset_capturings()
@pytest.mark.tryfirst
def pytest_internalerror(self, excinfo):
self.reset_capturings()
@contextlib.contextmanager
def item_capture_wrapper(self, item, when):
self.resumecapture_item(item)
if when == "call":
self.activate_funcargs(item)
yield
funcarg_outerr = self.deactivate_funcargs()
else:
yield
funcarg_outerr = None
out, err = self.suspendcapture(item) out, err = self.suspendcapture(item)
if funcarg_outerr is not None: if funcarg_outerr is not None:
out += funcarg_outerr[0] out += funcarg_outerr[0]
err += funcarg_outerr[1] err += funcarg_outerr[1]
item.add_report_section(call.when, "out", out) item.add_report_section(when, "out", out)
item.add_report_section(call.when, "err", err) item.add_report_section(when, "err", err)
error_capsysfderror = "cannot use capsys and capfd at the same time" error_capsysfderror = "cannot use capsys and capfd at the same time"
@ -263,10 +292,10 @@ def pytest_funcarg__capfd(request):
class CaptureFixture: class CaptureFixture:
def __init__(self, captureclass): def __init__(self, captureclass):
self._capture = captureclass() self._capture = captureclass(in_=False)
def _start(self): def _start(self):
self._capture.startall() self._capture.start_capturing()
def _finalize(self): def _finalize(self):
if hasattr(self, '_capture'): if hasattr(self, '_capture'):
@ -295,6 +324,8 @@ class FDCapture:
""" """
self.targetfd = targetfd self.targetfd = targetfd
if tmpfile is None and targetfd != 0: if tmpfile is None and targetfd != 0:
# this code path is covered in the tests
# but not used by a regular pytest run
f = tempfile.TemporaryFile('wb+') f = tempfile.TemporaryFile('wb+')
tmpfile = dupfile(f, encoding="UTF-8") tmpfile = dupfile(f, encoding="UTF-8")
f.close() f.close()
@ -390,13 +421,13 @@ class EncodedFile(object):
return getattr(self._stream, name) return getattr(self._stream, name)
class Capture(object): class StdCaptureBase(object):
def reset(self): def reset(self):
""" reset sys.stdout/stderr and return captured output as strings. """ """ reset sys.stdout/stderr and return captured output as strings. """
if hasattr(self, '_reset'): if hasattr(self, '_reset'):
raise ValueError("was already reset") raise ValueError("was already reset")
self._reset = True self._reset = True
outfile, errfile = self.done(save=False) outfile, errfile = self.stop_capturing(save=False)
out, err = "", "" out, err = "", ""
if outfile and not outfile.closed: if outfile and not outfile.closed:
out = outfile.read() out = outfile.read()
@ -406,14 +437,16 @@ class Capture(object):
errfile.close() errfile.close()
return out, err return out, err
def suspend(self): def pop_outerr_to_orig(self):
""" return current snapshot captures, memorize tempfiles. """ """ pop current snapshot out/err capture and flush to orig streams. """
outerr = self.readouterr() out, err = self.readouterr()
outfile, errfile = self.done() if out:
return outerr self.out.writeorg(out)
if err:
self.err.writeorg(err)
class StdCaptureFD(Capture): class StdCaptureFD(StdCaptureBase):
""" This class allows to capture writes to FD1 and FD2 """ This class allows to capture writes to FD1 and FD2
and may connect a NULL file to FD0 (and prevent and may connect a NULL file to FD0 (and prevent
reads from sys.stdin). If any of the 0,1,2 file descriptors reads from sys.stdin). If any of the 0,1,2 file descriptors
@ -464,7 +497,7 @@ class StdCaptureFD(Capture):
except OSError: except OSError:
pass pass
def startall(self): def start_capturing(self):
if hasattr(self, 'in_'): if hasattr(self, 'in_'):
self.in_.start() self.in_.start()
if hasattr(self, 'out'): if hasattr(self, 'out'):
@ -472,11 +505,10 @@ class StdCaptureFD(Capture):
if hasattr(self, 'err'): if hasattr(self, 'err'):
self.err.start() self.err.start()
def resume(self): #def pytest_sessionfinish(self):
""" resume capturing with original temp files. """ # self.reset_capturings()
self.startall()
def done(self, save=True): def stop_capturing(self, save=True):
""" return (outfile, errfile) and stop capturing. """ """ return (outfile, errfile) and stop capturing. """
outfile = errfile = None outfile = errfile = None
if hasattr(self, 'out') and not self.out.tmpfile.closed: if hasattr(self, 'out') and not self.out.tmpfile.closed:
@ -491,16 +523,15 @@ class StdCaptureFD(Capture):
def readouterr(self): def readouterr(self):
""" return snapshot value of stdout/stderr capturings. """ """ return snapshot value of stdout/stderr capturings. """
out = self._readsnapshot('out') return self._readsnapshot('out'), self._readsnapshot('err')
err = self._readsnapshot('err')
return out, err
def _readsnapshot(self, name): def _readsnapshot(self, name):
if hasattr(self, name): try:
f = getattr(self, name).tmpfile f = getattr(self, name).tmpfile
else: except AttributeError:
return ''
if f.tell() == 0:
return '' return ''
f.seek(0) f.seek(0)
res = f.read() res = f.read()
enc = getattr(f, "encoding", None) enc = getattr(f, "encoding", None)
@ -510,8 +541,17 @@ class StdCaptureFD(Capture):
f.seek(0) f.seek(0)
return res return res
class TextCapture(TextIO):
def __init__(self, oldout):
super(TextCapture, self).__init__()
self._oldout = oldout
class StdCapture(Capture): def writeorg(self, data):
self._oldout.write(data)
self._oldout.flush()
class StdCapture(StdCaptureBase):
""" This class allows to capture writes to sys.stdout|stderr "in-memory" """ This class allows to capture writes to sys.stdout|stderr "in-memory"
and will raise errors on tries to read from sys.stdin. It only and will raise errors on tries to read from sys.stdin. It only
modifies sys.stdout|stderr|stdin attributes and does not modifies sys.stdout|stderr|stdin attributes and does not
@ -522,15 +562,15 @@ class StdCapture(Capture):
self._olderr = sys.stderr self._olderr = sys.stderr
self._oldin = sys.stdin self._oldin = sys.stdin
if out and not hasattr(out, 'file'): if out and not hasattr(out, 'file'):
out = TextIO() out = TextCapture(self._oldout)
self.out = out self.out = out
if err: if err:
if not hasattr(err, 'write'): if not hasattr(err, 'write'):
err = TextIO() err = TextCapture(self._olderr)
self.err = err self.err = err
self.in_ = in_ self.in_ = in_
def startall(self): def start_capturing(self):
if self.out: if self.out:
sys.stdout = self.out sys.stdout = self.out
if self.err: if self.err:
@ -538,7 +578,7 @@ class StdCapture(Capture):
if self.in_: if self.in_:
sys.stdin = self.in_ = DontReadFromInput() sys.stdin = self.in_ = DontReadFromInput()
def done(self, save=True): def stop_capturing(self, save=True):
""" return (outfile, errfile) and stop capturing. """ """ return (outfile, errfile) and stop capturing. """
outfile = errfile = None outfile = errfile = None
if self.out and not self.out.closed: if self.out and not self.out.closed:
@ -553,9 +593,6 @@ class StdCapture(Capture):
sys.stdin = self._oldin sys.stdin = self._oldin
return outfile, errfile return outfile, errfile
def resume(self):
""" resume capturing with original temp files. """
self.startall()
def readouterr(self): def readouterr(self):
""" return snapshot value of stdout/stderr capturings. """ """ return snapshot value of stdout/stderr capturings. """

View File

@ -56,11 +56,15 @@ def _prepareconfig(args=None, plugins=None):
raise ValueError("not a string or argument list: %r" % (args,)) raise ValueError("not a string or argument list: %r" % (args,))
args = py.std.shlex.split(args) args = py.std.shlex.split(args)
pluginmanager = get_plugin_manager() pluginmanager = get_plugin_manager()
if plugins: try:
for plugin in plugins: if plugins:
pluginmanager.register(plugin) for plugin in plugins:
return pluginmanager.hook.pytest_cmdline_parse( pluginmanager.register(plugin)
pluginmanager=pluginmanager, args=args) return pluginmanager.hook.pytest_cmdline_parse(
pluginmanager=pluginmanager, args=args)
except Exception:
pluginmanager.ensure_shutdown()
raise
class PytestPluginManager(PluginManager): class PytestPluginManager(PluginManager):
def __init__(self, hookspecs=[hookspec]): def __init__(self, hookspecs=[hookspec]):
@ -612,6 +616,9 @@ class Config(object):
self.hook.pytest_logwarning(code=code, message=message, self.hook.pytest_logwarning(code=code, message=message,
fslocation=None, nodeid=None) fslocation=None, nodeid=None)
def get_terminal_writer(self):
return self.pluginmanager.getplugin("terminalreporter")._tw
def pytest_cmdline_parse(self, pluginmanager, args): def pytest_cmdline_parse(self, pluginmanager, args):
assert self == pluginmanager.config, (self, pluginmanager.config) assert self == pluginmanager.config, (self, pluginmanager.config)
self.parse(args) self.parse(args)

View File

@ -60,6 +60,7 @@ def pytest_addoption(parser):
def pytest_cmdline_main(config): def pytest_cmdline_main(config):
genscript = config.getvalue("genscript") genscript = config.getvalue("genscript")
if genscript: if genscript:
#tw = config.get_terminal_writer()
tw = py.io.TerminalWriter() tw = py.io.TerminalWriter()
deps = ['py', '_pytest', 'pytest'] deps = ['py', '_pytest', 'pytest']
if sys.version_info < (2,7): if sys.version_info < (2,7):

View File

@ -47,6 +47,8 @@ def pytest_unconfigure(config):
def pytest_cmdline_main(config): def pytest_cmdline_main(config):
if config.option.version: if config.option.version:
capman = config.pluginmanager.getplugin("capturemanager")
capman.reset_capturings()
p = py.path.local(pytest.__file__) p = py.path.local(pytest.__file__)
sys.stderr.write("This is pytest version %s, imported from %s\n" % sys.stderr.write("This is pytest version %s, imported from %s\n" %
(pytest.__version__, p)) (pytest.__version__, p))
@ -62,7 +64,7 @@ def pytest_cmdline_main(config):
return 0 return 0
def showhelp(config): def showhelp(config):
tw = py.io.TerminalWriter() tw = config.get_terminal_writer()
tw.write(config._parser.optparser.format_help()) tw.write(config._parser.optparser.format_help())
tw.line() tw.line()
tw.line() tw.line()

View File

@ -40,7 +40,7 @@ def pytest_addoption(parser):
def pytest_cmdline_main(config): def pytest_cmdline_main(config):
if config.option.markers: if config.option.markers:
config.do_configure() config.do_configure()
tw = py.io.TerminalWriter() tw = config.get_terminal_writer()
for line in config.getini("markers"): for line in config.getini("markers"):
name, rest = line.split(":", 1) name, rest = line.split(":", 1)
tw.write("@pytest.mark.%s:" % name, bold=True) tw.write("@pytest.mark.%s:" % name, bold=True)

View File

@ -34,10 +34,9 @@ class pytestPDB:
if item is not None: if item is not None:
capman = item.config.pluginmanager.getplugin("capturemanager") capman = item.config.pluginmanager.getplugin("capturemanager")
out, err = capman.suspendcapture() if capman:
#if hasattr(item, 'outerr'): capman.reset_capturings()
# item.outerr = (item.outerr[0] + out, item.outerr[1] + err) tw = item.config.get_terminal_writer()
tw = py.io.TerminalWriter()
tw.line() tw.line()
tw.sep(">", "PDB set_trace (IO-capturing turned off)") tw.sep(">", "PDB set_trace (IO-capturing turned off)")
py.std.pdb.Pdb().set_trace(frame) py.std.pdb.Pdb().set_trace(frame)
@ -46,19 +45,20 @@ def pdbitem(item):
pytestPDB.item = item pytestPDB.item = item
pytest_runtest_setup = pytest_runtest_call = pytest_runtest_teardown = pdbitem pytest_runtest_setup = pytest_runtest_call = pytest_runtest_teardown = pdbitem
@pytest.mark.tryfirst @pytest.mark.hookwrapper
def pytest_make_collect_report(__multicall__, collector): def pytest_make_collect_report(collector):
try: pytestPDB.collector = collector
pytestPDB.collector = collector yield
return __multicall__.execute() pytestPDB.collector = None
finally:
pytestPDB.collector = None
def pytest_runtest_makereport(): def pytest_runtest_makereport():
pytestPDB.item = None pytestPDB.item = None
class PdbInvoke: class PdbInvoke:
def pytest_exception_interact(self, node, call, report): def pytest_exception_interact(self, node, call, report):
capman = node.config.pluginmanager.getplugin("capturemanager")
if capman:
capman.reset_capturings()
return _enter_pdb(node, call.excinfo, report) return _enter_pdb(node, call.excinfo, report)
def pytest_internalerror(self, excrepr, excinfo): def pytest_internalerror(self, excrepr, excinfo):

View File

@ -885,7 +885,7 @@ def _showfixtures_main(config, session):
nodeid = "::".join(map(str, [curdir.bestrelpath(part[0])] + part[1:])) nodeid = "::".join(map(str, [curdir.bestrelpath(part[0])] + part[1:]))
nodeid.replace(session.fspath.sep, "/") nodeid.replace(session.fspath.sep, "/")
tw = py.io.TerminalWriter() tw = config.get_terminal_writer()
verbose = config.getvalue("verbose") verbose = config.getvalue("verbose")
fm = session._fixturemanager fm = session._fixturemanager

View File

@ -135,14 +135,13 @@ class CallInfo:
self.when = when self.when = when
self.start = time() self.start = time()
try: try:
try: self.result = func()
self.result = func() except KeyboardInterrupt:
except KeyboardInterrupt:
raise
except:
self.excinfo = py.code.ExceptionInfo()
finally:
self.stop = time() self.stop = time()
raise
except:
self.excinfo = py.code.ExceptionInfo()
self.stop = time()
def __repr__(self): def __repr__(self):
if self.excinfo: if self.excinfo:
@ -292,7 +291,8 @@ def pytest_make_collect_report(collector):
class CollectReport(BaseReport): class CollectReport(BaseReport):
def __init__(self, nodeid, outcome, longrepr, result, sections=(), **extra): def __init__(self, nodeid, outcome, longrepr, result,
sections=(), **extra):
self.nodeid = nodeid self.nodeid = nodeid
self.outcome = outcome self.outcome = outcome
self.longrepr = longrepr self.longrepr = longrepr

View File

@ -36,7 +36,10 @@ def pytest_addoption(parser):
def pytest_configure(config): def pytest_configure(config):
config.option.verbose -= config.option.quiet config.option.verbose -= config.option.quiet
reporter = TerminalReporter(config, sys.stdout) out = config.pluginmanager.getplugin("dupped_stdout")
#if out is None:
# out = sys.stdout
reporter = TerminalReporter(config, out)
config.pluginmanager.register(reporter, 'terminalreporter') config.pluginmanager.register(reporter, 'terminalreporter')
if config.option.debug or config.option.traceconfig: if config.option.debug or config.option.traceconfig:
def mywriter(tags, args): def mywriter(tags, args):
@ -44,6 +47,11 @@ def pytest_configure(config):
reporter.write_line("[traceconfig] " + msg) reporter.write_line("[traceconfig] " + msg)
config.trace.root.setprocessor("pytest:config", mywriter) config.trace.root.setprocessor("pytest:config", mywriter)
def get_terminal_writer(config):
tr = config.pluginmanager.getplugin("terminalreporter")
return tr._tw
def getreportopt(config): def getreportopt(config):
reportopts = "" reportopts = ""
optvalue = config.option.report optvalue = config.option.report

View File

@ -4,8 +4,8 @@ if __name__ == '__main__':
import cProfile import cProfile
import pytest import pytest
import pstats import pstats
script = sys.argv[1] if len(sys.argv) > 1 else "empty.py" script = sys.argv[1:] if len(sys.argv) > 1 else "empty.py"
stats = cProfile.run('pytest.cmdline.main([%r])' % script, 'prof') stats = cProfile.run('pytest.cmdline.main(%r)' % script, 'prof')
p = pstats.Stats("prof") p = pstats.Stats("prof")
p.strip_dirs() p.strip_dirs()
p.sort_stats('cumulative') p.sort_stats('cumulative')

View File

@ -736,14 +736,14 @@ class TestFDCapture:
class TestStdCapture: class TestStdCapture:
def getcapture(self, **kw): def getcapture(self, **kw):
cap = capture.StdCapture(**kw) cap = capture.StdCapture(**kw)
cap.startall() cap.start_capturing()
return cap return cap
def test_capturing_done_simple(self): def test_capturing_done_simple(self):
cap = self.getcapture() cap = self.getcapture()
sys.stdout.write("hello") sys.stdout.write("hello")
sys.stderr.write("world") sys.stderr.write("world")
outfile, errfile = cap.done() outfile, errfile = cap.stop_capturing()
s = outfile.read() s = outfile.read()
assert s == "hello" assert s == "hello"
s = errfile.read() s = errfile.read()
@ -787,6 +787,7 @@ class TestStdCapture:
print('\xa6') print('\xa6')
out, err = cap.readouterr() out, err = cap.readouterr()
assert out == py.builtin._totext('\ufffd\n', 'unicode-escape') assert out == py.builtin._totext('\ufffd\n', 'unicode-escape')
cap.reset()
def test_reset_twice_error(self): def test_reset_twice_error(self):
cap = self.getcapture() cap = self.getcapture()
@ -859,12 +860,13 @@ class TestStdCapture:
try: try:
print ("hello") print ("hello")
sys.stderr.write("error\n") sys.stderr.write("error\n")
out, err = cap.suspend() out, err = cap.readouterr()
cap.stop_capturing()
assert out == "hello\n" assert out == "hello\n"
assert not err assert not err
print ("in between") print ("in between")
sys.stderr.write("in between\n") sys.stderr.write("in between\n")
cap.resume() cap.start_capturing()
print ("after") print ("after")
sys.stderr.write("error_after\n") sys.stderr.write("error_after\n")
finally: finally:
@ -878,7 +880,7 @@ class TestStdCaptureFD(TestStdCapture):
def getcapture(self, **kw): def getcapture(self, **kw):
cap = capture.StdCaptureFD(**kw) cap = capture.StdCaptureFD(**kw)
cap.startall() cap.start_capturing()
return cap return cap
def test_intermingling(self): def test_intermingling(self):
@ -908,7 +910,7 @@ def test_stdcapture_fd_tmpfile(tmpfile):
try: try:
os.write(1, "hello".encode("ascii")) os.write(1, "hello".encode("ascii"))
os.write(2, "world".encode("ascii")) os.write(2, "world".encode("ascii"))
outf, errf = capfd.done() outf, errf = capfd.stop_capturing()
finally: finally:
capfd.reset() capfd.reset()
assert outf == tmpfile assert outf == tmpfile
@ -924,15 +926,15 @@ class TestStdCaptureFDinvalidFD:
def test_stdout(): def test_stdout():
os.close(1) os.close(1)
cap = StdCaptureFD(out=True, err=False, in_=False) cap = StdCaptureFD(out=True, err=False, in_=False)
cap.done() cap.stop_capturing()
def test_stderr(): def test_stderr():
os.close(2) os.close(2)
cap = StdCaptureFD(out=False, err=True, in_=False) cap = StdCaptureFD(out=False, err=True, in_=False)
cap.done() cap.stop_capturing()
def test_stdin(): def test_stdin():
os.close(0) os.close(0)
cap = StdCaptureFD(out=False, err=False, in_=True) cap = StdCaptureFD(out=False, err=False, in_=True)
cap.done() cap.stop_capturing()
""") """)
result = testdir.runpytest("--capture=fd") result = testdir.runpytest("--capture=fd")
assert result.ret == 0 assert result.ret == 0
@ -941,8 +943,8 @@ class TestStdCaptureFDinvalidFD:
def test_capture_not_started_but_reset(): def test_capture_not_started_but_reset():
capsys = capture.StdCapture() capsys = capture.StdCapture()
capsys.done() capsys.stop_capturing()
capsys.done() capsys.stop_capturing()
capsys.reset() capsys.reset()
@ -951,7 +953,7 @@ def test_capture_no_sys():
capsys = capture.StdCapture() capsys = capture.StdCapture()
try: try:
cap = capture.StdCaptureFD(patchsys=False) cap = capture.StdCaptureFD(patchsys=False)
cap.startall() cap.start_capturing()
sys.stdout.write("hello") sys.stdout.write("hello")
sys.stderr.write("world") sys.stderr.write("world")
oswritebytes(1, "1") oswritebytes(1, "1")
@ -970,10 +972,9 @@ def test_fdcapture_tmpfile_remains_the_same(tmpfile, use):
tmpfile = True tmpfile = True
cap = capture.StdCaptureFD(out=False, err=tmpfile) cap = capture.StdCaptureFD(out=False, err=tmpfile)
try: try:
cap.startall() cap.start_capturing()
capfile = cap.err.tmpfile capfile = cap.err.tmpfile
cap.suspend() cap.readouterr()
cap.resume()
finally: finally:
cap.reset() cap.reset()
capfile2 = cap.err.tmpfile capfile2 = cap.err.tmpfile
@ -990,22 +991,25 @@ def test_capturing_and_logging_fundamentals(testdir, method):
import py, logging import py, logging
from _pytest import capture from _pytest import capture
cap = capture.%s(out=False, in_=False) cap = capture.%s(out=False, in_=False)
cap.startall() cap.start_capturing()
logging.warn("hello1") logging.warn("hello1")
outerr = cap.suspend() outerr = cap.readouterr()
print ("suspend, captured %%s" %%(outerr,)) print ("suspend, captured %%s" %%(outerr,))
logging.warn("hello2") logging.warn("hello2")
cap.resume() cap.pop_outerr_to_orig()
logging.warn("hello3") logging.warn("hello3")
outerr = cap.suspend() outerr = cap.readouterr()
print ("suspend2, captured %%s" %% (outerr,)) print ("suspend2, captured %%s" %% (outerr,))
""" % (method,)) """ % (method,))
result = testdir.runpython(p) result = testdir.runpython(p)
result.stdout.fnmatch_lines([ result.stdout.fnmatch_lines("""
"suspend, captured*hello1*", suspend, captured*hello1*
"suspend2, captured*hello2*WARNING:root:hello3*", suspend2, captured*WARNING:root:hello3*
]) """)
result.stderr.fnmatch_lines("""
WARNING:root:hello2
""")
assert "atexit" not in result.stderr.str() assert "atexit" not in result.stderr.str()