reports.py 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. import py
  2. from _pytest._code.code import TerminalRepr
  3. def getslaveinfoline(node):
  4. try:
  5. return node._slaveinfocache
  6. except AttributeError:
  7. d = node.slaveinfo
  8. ver = "%s.%s.%s" % d["version_info"][:3]
  9. node._slaveinfocache = s = "[%s] %s -- Python %s %s" % (
  10. d["id"],
  11. d["sysplatform"],
  12. ver,
  13. d["executable"],
  14. )
  15. return s
  16. class BaseReport(object):
  17. def __init__(self, **kw):
  18. self.__dict__.update(kw)
  19. def toterminal(self, out):
  20. if hasattr(self, "node"):
  21. out.line(getslaveinfoline(self.node))
  22. longrepr = self.longrepr
  23. if longrepr is None:
  24. return
  25. if hasattr(longrepr, "toterminal"):
  26. longrepr.toterminal(out)
  27. else:
  28. try:
  29. out.line(longrepr)
  30. except UnicodeEncodeError:
  31. out.line("<unprintable longrepr>")
  32. def get_sections(self, prefix):
  33. for name, content in self.sections:
  34. if name.startswith(prefix):
  35. yield prefix, content
  36. @property
  37. def longreprtext(self):
  38. """
  39. Read-only property that returns the full string representation
  40. of ``longrepr``.
  41. .. versionadded:: 3.0
  42. """
  43. tw = py.io.TerminalWriter(stringio=True)
  44. tw.hasmarkup = False
  45. self.toterminal(tw)
  46. exc = tw.stringio.getvalue()
  47. return exc.strip()
  48. @property
  49. def caplog(self):
  50. """Return captured log lines, if log capturing is enabled
  51. .. versionadded:: 3.5
  52. """
  53. return "\n".join(
  54. content for (prefix, content) in self.get_sections("Captured log")
  55. )
  56. @property
  57. def capstdout(self):
  58. """Return captured text from stdout, if capturing is enabled
  59. .. versionadded:: 3.0
  60. """
  61. return "".join(
  62. content for (prefix, content) in self.get_sections("Captured stdout")
  63. )
  64. @property
  65. def capstderr(self):
  66. """Return captured text from stderr, if capturing is enabled
  67. .. versionadded:: 3.0
  68. """
  69. return "".join(
  70. content for (prefix, content) in self.get_sections("Captured stderr")
  71. )
  72. passed = property(lambda x: x.outcome == "passed")
  73. failed = property(lambda x: x.outcome == "failed")
  74. skipped = property(lambda x: x.outcome == "skipped")
  75. @property
  76. def fspath(self):
  77. return self.nodeid.split("::")[0]
  78. class TestReport(BaseReport):
  79. """ Basic test report object (also used for setup and teardown calls if
  80. they fail).
  81. """
  82. def __init__(
  83. self,
  84. nodeid,
  85. location,
  86. keywords,
  87. outcome,
  88. longrepr,
  89. when,
  90. sections=(),
  91. duration=0,
  92. user_properties=(),
  93. **extra
  94. ):
  95. #: normalized collection node id
  96. self.nodeid = nodeid
  97. #: a (filesystempath, lineno, domaininfo) tuple indicating the
  98. #: actual location of a test item - it might be different from the
  99. #: collected one e.g. if a method is inherited from a different module.
  100. self.location = location
  101. #: a name -> value dictionary containing all keywords and
  102. #: markers associated with a test invocation.
  103. self.keywords = keywords
  104. #: test outcome, always one of "passed", "failed", "skipped".
  105. self.outcome = outcome
  106. #: None or a failure representation.
  107. self.longrepr = longrepr
  108. #: one of 'setup', 'call', 'teardown' to indicate runtest phase.
  109. self.when = when
  110. #: user properties is a list of tuples (name, value) that holds user
  111. #: defined properties of the test
  112. self.user_properties = user_properties
  113. #: list of pairs ``(str, str)`` of extra information which needs to
  114. #: marshallable. Used by pytest to add captured text
  115. #: from ``stdout`` and ``stderr``, but may be used by other plugins
  116. #: to add arbitrary information to reports.
  117. self.sections = list(sections)
  118. #: time it took to run just the test
  119. self.duration = duration
  120. self.__dict__.update(extra)
  121. def __repr__(self):
  122. return "<TestReport %r when=%r outcome=%r>" % (
  123. self.nodeid,
  124. self.when,
  125. self.outcome,
  126. )
  127. class TeardownErrorReport(BaseReport):
  128. outcome = "failed"
  129. when = "teardown"
  130. def __init__(self, longrepr, **extra):
  131. self.longrepr = longrepr
  132. self.sections = []
  133. self.__dict__.update(extra)
  134. class CollectReport(BaseReport):
  135. def __init__(self, nodeid, outcome, longrepr, result, sections=(), **extra):
  136. self.nodeid = nodeid
  137. self.outcome = outcome
  138. self.longrepr = longrepr
  139. self.result = result or []
  140. self.sections = list(sections)
  141. self.__dict__.update(extra)
  142. @property
  143. def location(self):
  144. return (self.fspath, None, self.fspath)
  145. def __repr__(self):
  146. return "<CollectReport %r lenresult=%s outcome=%r>" % (
  147. self.nodeid,
  148. len(self.result),
  149. self.outcome,
  150. )
  151. class CollectErrorRepr(TerminalRepr):
  152. def __init__(self, msg):
  153. self.longrepr = msg
  154. def toterminal(self, out):
  155. out.line(self.longrepr, red=True)