outcomes.py 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. """
  2. exception classes and constants handling test outcomes
  3. as well as functions creating them
  4. """
  5. from __future__ import absolute_import, division, print_function
  6. import sys
  7. class OutcomeException(BaseException):
  8. """ OutcomeException and its subclass instances indicate and
  9. contain info about test and collection outcomes.
  10. """
  11. def __init__(self, msg=None, pytrace=True):
  12. BaseException.__init__(self, msg)
  13. self.msg = msg
  14. self.pytrace = pytrace
  15. def __repr__(self):
  16. if self.msg:
  17. val = self.msg
  18. if isinstance(val, bytes):
  19. val = val.decode("UTF-8", errors="replace")
  20. return val
  21. return "<%s instance>" % (self.__class__.__name__,)
  22. __str__ = __repr__
  23. TEST_OUTCOME = (OutcomeException, Exception)
  24. class Skipped(OutcomeException):
  25. # XXX hackish: on 3k we fake to live in the builtins
  26. # in order to have Skipped exception printing shorter/nicer
  27. __module__ = "builtins"
  28. def __init__(self, msg=None, pytrace=True, allow_module_level=False):
  29. OutcomeException.__init__(self, msg=msg, pytrace=pytrace)
  30. self.allow_module_level = allow_module_level
  31. class Failed(OutcomeException):
  32. """ raised from an explicit call to pytest.fail() """
  33. __module__ = "builtins"
  34. class Exit(KeyboardInterrupt):
  35. """ raised for immediate program exits (no tracebacks/summaries)"""
  36. def __init__(self, msg="unknown reason"):
  37. self.msg = msg
  38. KeyboardInterrupt.__init__(self, msg)
  39. # exposed helper methods
  40. def exit(msg):
  41. """ exit testing process as if KeyboardInterrupt was triggered. """
  42. __tracebackhide__ = True
  43. raise Exit(msg)
  44. exit.Exception = Exit
  45. def skip(msg="", **kwargs):
  46. """ skip an executing test with the given message. Note: it's usually
  47. better to use the pytest.mark.skipif marker to declare a test to be
  48. skipped under certain conditions like mismatching platforms or
  49. dependencies. See the pytest_skipping plugin for details.
  50. :kwarg bool allow_module_level: allows this function to be called at
  51. module level, skipping the rest of the module. Default to False.
  52. """
  53. __tracebackhide__ = True
  54. allow_module_level = kwargs.pop("allow_module_level", False)
  55. if kwargs:
  56. keys = [k for k in kwargs.keys()]
  57. raise TypeError("unexpected keyword arguments: {}".format(keys))
  58. raise Skipped(msg=msg, allow_module_level=allow_module_level)
  59. skip.Exception = Skipped
  60. def fail(msg="", pytrace=True):
  61. """ explicitly fail a currently-executing test with the given Message.
  62. :arg pytrace: if false the msg represents the full failure information
  63. and no python traceback will be reported.
  64. """
  65. __tracebackhide__ = True
  66. raise Failed(msg=msg, pytrace=pytrace)
  67. fail.Exception = Failed
  68. class XFailed(fail.Exception):
  69. """ raised from an explicit call to pytest.xfail() """
  70. def xfail(reason=""):
  71. """ xfail an executing test or setup functions with the given reason."""
  72. __tracebackhide__ = True
  73. raise XFailed(reason)
  74. xfail.Exception = XFailed
  75. def importorskip(modname, minversion=None):
  76. """ return imported module if it has at least "minversion" as its
  77. __version__ attribute. If no minversion is specified the a skip
  78. is only triggered if the module can not be imported.
  79. """
  80. import warnings
  81. __tracebackhide__ = True
  82. compile(modname, "", "eval") # to catch syntaxerrors
  83. should_skip = False
  84. with warnings.catch_warnings():
  85. # make sure to ignore ImportWarnings that might happen because
  86. # of existing directories with the same name we're trying to
  87. # import but without a __init__.py file
  88. warnings.simplefilter("ignore")
  89. try:
  90. __import__(modname)
  91. except ImportError:
  92. # Do not raise chained exception here(#1485)
  93. should_skip = True
  94. if should_skip:
  95. raise Skipped("could not import %r" % (modname,), allow_module_level=True)
  96. mod = sys.modules[modname]
  97. if minversion is None:
  98. return mod
  99. verattr = getattr(mod, "__version__", None)
  100. if minversion is not None:
  101. try:
  102. from pkg_resources import parse_version as pv
  103. except ImportError:
  104. raise Skipped(
  105. "we have a required version for %r but can not import "
  106. "pkg_resources to parse version strings." % (modname,),
  107. allow_module_level=True,
  108. )
  109. if verattr is None or pv(verattr) < pv(minversion):
  110. raise Skipped(
  111. "module %r has __version__ %r, required is: %r"
  112. % (modname, verattr, minversion),
  113. allow_module_level=True,
  114. )
  115. return mod