capture.py 3.3 KB

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