diff --git a/py/_io/capture.py b/py/_io/capture.py index b510d399d..d715d85bb 100644 --- a/py/_io/capture.py +++ b/py/_io/capture.py @@ -175,7 +175,8 @@ class Capture(object): class StdCaptureFD(Capture): """ This class allows to capture writes to FD1 and FD2 and may connect a NULL file to FD0 (and prevent - reads from sys.stdin) + reads from sys.stdin). If any of the 0,1,2 file descriptors + is invalid it will not be captured. """ def __init__(self, out=True, err=True, mixed=False, in_=True, patchsys=True, now=True): @@ -192,13 +193,19 @@ class StdCaptureFD(Capture): mixed = self._options['mixed'] self.in_ = in_ if in_: - self._oldin = (sys.stdin, os.dup(0)) + try: + self._oldin = (sys.stdin, os.dup(0)) + except OSError: + pass if out: tmpfile = None if hasattr(out, 'write'): tmpfile = out - self.out = py.io.FDCapture(1, tmpfile=tmpfile, now=False) - self._options['out'] = self.out.tmpfile + try: + self.out = FDCapture(1, tmpfile=tmpfile, now=False) + self._options['out'] = self.out.tmpfile + except OSError: + pass if err: if out and mixed: tmpfile = self.out.tmpfile @@ -206,8 +213,11 @@ class StdCaptureFD(Capture): tmpfile = err else: tmpfile = None - self.err = py.io.FDCapture(2, tmpfile=tmpfile, now=False) - self._options['err'] = self.err.tmpfile + try: + self.err = FDCapture(2, tmpfile=tmpfile, now=False) + self._options['err'] = self.err.tmpfile + except OSError: + pass def startall(self): if self.in_: diff --git a/testing/io_/test_capture.py b/testing/io_/test_capture.py index 8cc6a8e91..a48701d5d 100644 --- a/testing/io_/test_capture.py +++ b/testing/io_/test_capture.py @@ -360,6 +360,28 @@ def test_stdcapture_fd_tmpfile(tmpfile): outf, errf = capfd.done() assert outf == tmpfile +class TestStdCaptureFDinvalidFD: + pytestmark = needsdup + def test_stdcapture_fd_invalid_fd(self, testdir): + testdir.makepyfile(""" + import py, os + def test_stdout(): + os.close(1) + cap = py.io.StdCaptureFD(out=True, err=False, in_=False) + cap.done() + def test_stderr(): + os.close(2) + cap = py.io.StdCaptureFD(out=False, err=True, in_=False) + cap.done() + def test_stdin(): + os.close(0) + cap = py.io.StdCaptureFD(out=False, err=False, in_=True) + cap.done() + """) + result = testdir.runpytest("--capture=fd") + assert result.ret == 0 + assert result.parseoutcomes()['passed'] == 3 + def test_capture_not_started_but_reset(): capsys = py.io.StdCapture(now=False) capsys.done()