outcomes.py 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. # -*- coding: utf-8 -*-
  2. """
  3. exception classes and constants handling test outcomes
  4. as well as functions creating them
  5. """
  6. from __future__ import absolute_import
  7. from __future__ import division
  8. from __future__ import print_function
  9. import sys
  10. from packaging.version import Version
  11. class OutcomeException(BaseException):
  12. """ OutcomeException and its subclass instances indicate and
  13. contain info about test and collection outcomes.
  14. """
  15. def __init__(self, msg=None, pytrace=True):
  16. BaseException.__init__(self, msg)
  17. self.msg = msg
  18. self.pytrace = pytrace
  19. def __repr__(self):
  20. if self.msg:
  21. val = self.msg
  22. if isinstance(val, bytes):
  23. val = val.decode("UTF-8", errors="replace")
  24. return val
  25. return "<%s instance>" % (self.__class__.__name__,)
  26. __str__ = __repr__
  27. TEST_OUTCOME = (OutcomeException, Exception)
  28. class Skipped(OutcomeException):
  29. # XXX hackish: on 3k we fake to live in the builtins
  30. # in order to have Skipped exception printing shorter/nicer
  31. __module__ = "builtins"
  32. def __init__(self, msg=None, pytrace=True, allow_module_level=False):
  33. OutcomeException.__init__(self, msg=msg, pytrace=pytrace)
  34. self.allow_module_level = allow_module_level
  35. class Failed(OutcomeException):
  36. """ raised from an explicit call to pytest.fail() """
  37. __module__ = "builtins"
  38. class Exit(Exception):
  39. """ raised for immediate program exits (no tracebacks/summaries)"""
  40. def __init__(self, msg="unknown reason", returncode=None):
  41. self.msg = msg
  42. self.returncode = returncode
  43. super(Exit, self).__init__(msg)
  44. # exposed helper methods
  45. def exit(msg, returncode=None):
  46. """
  47. Exit testing process.
  48. :param str msg: message to display upon exit.
  49. :param int returncode: return code to be used when exiting pytest.
  50. """
  51. __tracebackhide__ = True
  52. raise Exit(msg, returncode)
  53. exit.Exception = Exit
  54. def skip(msg="", **kwargs):
  55. """
  56. Skip an executing test with the given message.
  57. This function should be called only during testing (setup, call or teardown) or
  58. during collection by using the ``allow_module_level`` flag. This function can
  59. be called in doctests as well.
  60. :kwarg bool allow_module_level: allows this function to be called at
  61. module level, skipping the rest of the module. Default to False.
  62. .. note::
  63. It is better to use the :ref:`pytest.mark.skipif ref` marker when possible to declare a test to be
  64. skipped under certain conditions like mismatching platforms or
  65. dependencies.
  66. Similarly, use the ``# doctest: +SKIP`` directive (see `doctest.SKIP
  67. <https://docs.python.org/3/library/doctest.html#doctest.SKIP>`_)
  68. to skip a doctest statically.
  69. """
  70. __tracebackhide__ = True
  71. allow_module_level = kwargs.pop("allow_module_level", False)
  72. if kwargs:
  73. raise TypeError("unexpected keyword arguments: {}".format(sorted(kwargs)))
  74. raise Skipped(msg=msg, allow_module_level=allow_module_level)
  75. skip.Exception = Skipped
  76. def fail(msg="", pytrace=True):
  77. """
  78. Explicitly fail an executing test with the given message.
  79. :param str msg: the message to show the user as reason for the failure.
  80. :param bool pytrace: if false the msg represents the full failure information and no
  81. python traceback will be reported.
  82. """
  83. __tracebackhide__ = True
  84. raise Failed(msg=msg, pytrace=pytrace)
  85. fail.Exception = Failed
  86. class XFailed(fail.Exception):
  87. """ raised from an explicit call to pytest.xfail() """
  88. def xfail(reason=""):
  89. """
  90. Imperatively xfail an executing test or setup functions with the given reason.
  91. This function should be called only during testing (setup, call or teardown).
  92. .. note::
  93. It is better to use the :ref:`pytest.mark.xfail ref` marker when possible to declare a test to be
  94. xfailed under certain conditions like known bugs or missing features.
  95. """
  96. __tracebackhide__ = True
  97. raise XFailed(reason)
  98. xfail.Exception = XFailed
  99. def importorskip(modname, minversion=None, reason=None):
  100. """Imports and returns the requested module ``modname``, or skip the current test
  101. if the module cannot be imported.
  102. :param str modname: the name of the module to import
  103. :param str minversion: if given, the imported module ``__version__`` attribute must be
  104. at least this minimal version, otherwise the test is still skipped.
  105. :param str reason: if given, this reason is shown as the message when the module
  106. cannot be imported.
  107. """
  108. import warnings
  109. __tracebackhide__ = True
  110. compile(modname, "", "eval") # to catch syntaxerrors
  111. import_exc = None
  112. with warnings.catch_warnings():
  113. # make sure to ignore ImportWarnings that might happen because
  114. # of existing directories with the same name we're trying to
  115. # import but without a __init__.py file
  116. warnings.simplefilter("ignore")
  117. try:
  118. __import__(modname)
  119. except ImportError as exc:
  120. # Do not raise chained exception here(#1485)
  121. import_exc = exc
  122. if import_exc:
  123. if reason is None:
  124. reason = "could not import %r: %s" % (modname, import_exc)
  125. raise Skipped(reason, allow_module_level=True)
  126. mod = sys.modules[modname]
  127. if minversion is None:
  128. return mod
  129. verattr = getattr(mod, "__version__", None)
  130. if minversion is not None:
  131. if verattr is None or Version(verattr) < Version(minversion):
  132. raise Skipped(
  133. "module %r has __version__ %r, required is: %r"
  134. % (modname, verattr, minversion),
  135. allow_module_level=True,
  136. )
  137. return mod