1 | """ |
---|
2 | This plugin captures stdout during test execution. If the test fails |
---|
3 | or raises an error, the captured output will be appended to the error |
---|
4 | or failure output. It is enabled by default but can be disabled with |
---|
5 | the options ``-s`` or ``--nocapture``. |
---|
6 | |
---|
7 | :Options: |
---|
8 | ``--nocapture`` |
---|
9 | Don't capture stdout (any stdout output will be printed immediately) |
---|
10 | |
---|
11 | """ |
---|
12 | import logging |
---|
13 | import os |
---|
14 | import sys |
---|
15 | from nose.plugins.base import Plugin |
---|
16 | from nose.util import ln |
---|
17 | from StringIO import StringIO |
---|
18 | |
---|
19 | |
---|
20 | log = logging.getLogger(__name__) |
---|
21 | |
---|
22 | class Capture(Plugin): |
---|
23 | """ |
---|
24 | Output capture plugin. Enabled by default. Disable with ``-s`` or |
---|
25 | ``--nocapture``. This plugin captures stdout during test execution, |
---|
26 | appending any output captured to the error or failure output, |
---|
27 | should the test fail or raise an error. |
---|
28 | """ |
---|
29 | enabled = True |
---|
30 | env_opt = 'NOSE_NOCAPTURE' |
---|
31 | name = 'capture' |
---|
32 | score = 500 |
---|
33 | |
---|
34 | def __init__(self): |
---|
35 | self.stdout = [] |
---|
36 | self._buf = None |
---|
37 | |
---|
38 | def options(self, parser, env): |
---|
39 | """Register commandline options |
---|
40 | """ |
---|
41 | parser.add_option( |
---|
42 | "-s", "--nocapture", action="store_false", |
---|
43 | default=not env.get(self.env_opt), dest="capture", |
---|
44 | help="Don't capture stdout (any stdout output " |
---|
45 | "will be printed immediately) [NOSE_NOCAPTURE]") |
---|
46 | |
---|
47 | def configure(self, options, conf): |
---|
48 | """Configure plugin. Plugin is enabled by default. |
---|
49 | """ |
---|
50 | self.conf = conf |
---|
51 | if not options.capture: |
---|
52 | self.enabled = False |
---|
53 | |
---|
54 | def afterTest(self, test): |
---|
55 | """Clear capture buffer. |
---|
56 | """ |
---|
57 | self.end() |
---|
58 | self._buf = None |
---|
59 | |
---|
60 | def begin(self): |
---|
61 | """Replace sys.stdout with capture buffer. |
---|
62 | """ |
---|
63 | self.start() # get an early handle on sys.stdout |
---|
64 | |
---|
65 | def beforeTest(self, test): |
---|
66 | """Flush capture buffer. |
---|
67 | """ |
---|
68 | self.start() |
---|
69 | |
---|
70 | def formatError(self, test, err): |
---|
71 | """Add captured output to error report. |
---|
72 | """ |
---|
73 | test.capturedOutput = output = self.buffer |
---|
74 | self._buf = None |
---|
75 | if not output: |
---|
76 | # Don't return None as that will prevent other |
---|
77 | # formatters from formatting and remove earlier formatters |
---|
78 | # formats, instead return the err we got |
---|
79 | return err |
---|
80 | ec, ev, tb = err |
---|
81 | return (ec, self.addCaptureToErr(ev, output), tb) |
---|
82 | |
---|
83 | def formatFailure(self, test, err): |
---|
84 | """Add captured output to failure report. |
---|
85 | """ |
---|
86 | return self.formatError(test, err) |
---|
87 | |
---|
88 | def addCaptureToErr(self, ev, output): |
---|
89 | return '\n'.join([str(ev) , ln('>> begin captured stdout <<'), |
---|
90 | output, ln('>> end captured stdout <<')]) |
---|
91 | |
---|
92 | def start(self): |
---|
93 | self.stdout.append(sys.stdout) |
---|
94 | self._buf = StringIO() |
---|
95 | sys.stdout = self._buf |
---|
96 | |
---|
97 | def end(self): |
---|
98 | if self.stdout: |
---|
99 | sys.stdout = self.stdout.pop() |
---|
100 | |
---|
101 | def finalize(self, result): |
---|
102 | """Restore stdout. |
---|
103 | """ |
---|
104 | while self.stdout: |
---|
105 | self.end() |
---|
106 | |
---|
107 | def _get_buffer(self): |
---|
108 | if self._buf is not None: |
---|
109 | return self._buf.getvalue() |
---|
110 | |
---|
111 | buffer = property(_get_buffer, None, None, |
---|
112 | """Captured stdout output.""") |
---|