sources for stdcapture.py [rev. 38799]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
import os
import sys
import py
try: from cStringIO import StringIO
except ImportError: from StringIO import StringIO
class Capture(object):
    def call(cls, func, *args, **kwargs): 
        """ return a (res, out, err) tuple where
            out and err represent the output/error output
            during function execution. 
            call the given function with args/kwargs
            and capture output/error during its execution. 
        """ 
        so = cls()
        try: 
            res = func(*args, **kwargs)
        finally: 
            out, err = so.reset()
        return res, out, err 
    call = classmethod(call) 
    def reset(self): 
        """ reset sys.stdout and sys.stderr
            returns a tuple of file objects (out, err) for the captured
            data
        """
        outfile, errfile = self.done()
        return outfile.read(), errfile.read()
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)
    """
    def __init__(self, out=True, err=True, mixed=False, in_=True, patchsys=True): 
        if in_:
            self._oldin = (sys.stdin, os.dup(0))
            sys.stdin  = DontReadFromInput()
            fd = os.open(devnullpath, os.O_RDONLY)
            os.dup2(fd, 0)
            os.close(fd)
        if out: 
            self.out = py.io.FDCapture(1) 
            if patchsys: 
                self.out.setasfile('stdout')
        if err: 
            if mixed and out:
                tmpfile = self.out.tmpfile 
            else:
                tmpfile = None    
            self.err = py.io.FDCapture(2, tmpfile=tmpfile) 
            if patchsys: 
                self.err.setasfile('stderr')
    def done(self):
        """ return (outfile, errfile) and stop capturing. """
        outfile = errfile = emptyfile
        if hasattr(self, 'out'): 
            outfile = self.out.done() 
        if hasattr(self, 'err'): 
            errfile = self.err.done() 
        if hasattr(self, '_oldin'):
            oldsys, oldfd = self._oldin 
            os.dup2(oldfd, 0)
            os.close(oldfd)
            sys.stdin = oldsys 
        return outfile, errfile 
class StdCapture(Capture):
    """ 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
        modifies sys.stdout|stderr|stdin attributes and does not 
        touch underlying File Descriptors (use StdCaptureFD for that). 
    """
    def __init__(self, out=True, err=True, in_=True, mixed=False):
        self._out = out
        self._err = err 
        self._in = in_
        if out: 
            self.oldout = sys.stdout
            sys.stdout = self.newout = StringIO()
        if err: 
            self.olderr = sys.stderr
            if out and mixed: 
                newerr = self.newout 
            else:
                newerr = StringIO()
            sys.stderr = self.newerr = newerr
        if in_:
            self.oldin  = sys.stdin
            sys.stdin  = self.newin  = DontReadFromInput()
    def reset(self):
        """ return captured output as strings and restore sys.stdout/err."""
        x, y = self.done() 
        return x.read(), y.read() 
    def done(self): 
        """ return (outfile, errfile) and stop capturing. """
        o,e = sys.stdout, sys.stderr
        outfile = errfile = emptyfile
        if self._out: 
            try:
                sys.stdout = self.oldout 
            except AttributeError:
                raise IOError("stdout capturing already reset")
            del self.oldout
            outfile = self.newout
            outfile.seek(0)
        if self._err: 
            try:
                sys.stderr = self.olderr 
            except AttributeError:
                raise IOError("stderr capturing already reset")
            del self.olderr 
            errfile = self.newerr 
            errfile.seek(0)
        if self._in:
            sys.stdin = self.oldin 
        return outfile, errfile
class DontReadFromInput:
    """Temporary stub class.  Ideally when stdin is accessed, the
    capturing should be turned off, with possibly all data captured
    so far sent to the screen.  This should be configurable, though,
    because in automated test runs it is better to crash than
    hang indefinitely.
    """
    def read(self, *args):
        raise IOError("reading from stdin while output is captured")
    readline = read
    readlines = read
    __iter__ = read
try:
    devnullpath = os.devnull
except AttributeError:
    if os.name == 'nt':
        devnullpath = 'NUL'
    else:
        devnullpath = '/dev/null'
emptyfile = StringIO()