_pytesttester.py 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. """
  2. Pytest test running.
  3. This module implements the ``test()`` function for NumPy modules. The usual
  4. boiler plate for doing that is to put the following in the module
  5. ``__init__.py`` file::
  6. from numpy._pytesttester import PytestTester
  7. test = PytestTester(__name__).test
  8. del PytestTester
  9. Warnings filtering and other runtime settings should be dealt with in the
  10. ``pytest.ini`` file in the numpy repo root. The behavior of the test depends on
  11. whether or not that file is found as follows:
  12. * ``pytest.ini`` is present (develop mode)
  13. All warnings except those explicily filtered out are raised as error.
  14. * ``pytest.ini`` is absent (release mode)
  15. DeprecationWarnings and PendingDeprecationWarnings are ignored, other
  16. warnings are passed through.
  17. In practice, tests run from the numpy repo are run in develop mode. That
  18. includes the standard ``python runtests.py`` invocation.
  19. This module is imported by every numpy subpackage, so lies at the top level to
  20. simplify circular import issues. For the same reason, it contains no numpy
  21. imports at module scope, instead importing numpy within function calls.
  22. """
  23. from __future__ import division, absolute_import, print_function
  24. import sys
  25. import os
  26. __all__ = ['PytestTester']
  27. def _show_numpy_info():
  28. import numpy as np
  29. print("NumPy version %s" % np.__version__)
  30. relaxed_strides = np.ones((10, 1), order="C").flags.f_contiguous
  31. print("NumPy relaxed strides checking option:", relaxed_strides)
  32. class PytestTester(object):
  33. """
  34. Pytest test runner.
  35. A test function is typically added to a package's __init__.py like so::
  36. from numpy._pytesttester import PytestTester
  37. test = PytestTester(__name__).test
  38. del PytestTester
  39. Calling this test function finds and runs all tests associated with the
  40. module and all its sub-modules.
  41. Attributes
  42. ----------
  43. module_name : str
  44. Full path to the package to test.
  45. Parameters
  46. ----------
  47. module_name : module name
  48. The name of the module to test.
  49. Notes
  50. -----
  51. Unlike the previous ``nose``-based implementation, this class is not
  52. publicly exposed as it performs some ``numpy``-specific warning
  53. suppression.
  54. """
  55. def __init__(self, module_name):
  56. self.module_name = module_name
  57. def __call__(self, label='fast', verbose=1, extra_argv=None,
  58. doctests=False, coverage=False, durations=-1, tests=None):
  59. """
  60. Run tests for module using pytest.
  61. Parameters
  62. ----------
  63. label : {'fast', 'full'}, optional
  64. Identifies the tests to run. When set to 'fast', tests decorated
  65. with `pytest.mark.slow` are skipped, when 'full', the slow marker
  66. is ignored.
  67. verbose : int, optional
  68. Verbosity value for test outputs, in the range 1-3. Default is 1.
  69. extra_argv : list, optional
  70. List with any extra arguments to pass to pytests.
  71. doctests : bool, optional
  72. .. note:: Not supported
  73. coverage : bool, optional
  74. If True, report coverage of NumPy code. Default is False.
  75. Requires installation of (pip) pytest-cov.
  76. durations : int, optional
  77. If < 0, do nothing, If 0, report time of all tests, if > 0,
  78. report the time of the slowest `timer` tests. Default is -1.
  79. tests : test or list of tests
  80. Tests to be executed with pytest '--pyargs'
  81. Returns
  82. -------
  83. result : bool
  84. Return True on success, false otherwise.
  85. Notes
  86. -----
  87. Each NumPy module exposes `test` in its namespace to run all tests for
  88. it. For example, to run all tests for numpy.lib:
  89. >>> np.lib.test() #doctest: +SKIP
  90. Examples
  91. --------
  92. >>> result = np.lib.test() #doctest: +SKIP
  93. ...
  94. 1023 passed, 2 skipped, 6 deselected, 1 xfailed in 10.39 seconds
  95. >>> result
  96. True
  97. """
  98. import pytest
  99. import warnings
  100. #FIXME This is no longer needed? Assume it was for use in tests.
  101. # cap verbosity at 3, which is equivalent to the pytest '-vv' option
  102. #from . import utils
  103. #verbose = min(int(verbose), 3)
  104. #utils.verbose = verbose
  105. #
  106. module = sys.modules[self.module_name]
  107. module_path = os.path.abspath(module.__path__[0])
  108. # setup the pytest arguments
  109. pytest_args = ["-l"]
  110. # offset verbosity. The "-q" cancels a "-v".
  111. pytest_args += ["-q"]
  112. # Filter out distutils cpu warnings (could be localized to
  113. # distutils tests). ASV has problems with top level import,
  114. # so fetch module for suppression here.
  115. with warnings.catch_warnings():
  116. warnings.simplefilter("always")
  117. from numpy.distutils import cpuinfo
  118. # Filter out annoying import messages. Want these in both develop and
  119. # release mode.
  120. pytest_args += [
  121. "-W ignore:Not importing directory",
  122. "-W ignore:numpy.dtype size changed",
  123. "-W ignore:numpy.ufunc size changed",
  124. "-W ignore::UserWarning:cpuinfo",
  125. ]
  126. # When testing matrices, ignore their PendingDeprecationWarnings
  127. pytest_args += [
  128. "-W ignore:the matrix subclass is not",
  129. ]
  130. # Ignore python2.7 -3 warnings
  131. pytest_args += [
  132. r"-W ignore:sys\.exc_clear\(\) not supported in 3\.x:DeprecationWarning",
  133. r"-W ignore:in 3\.x, __setslice__:DeprecationWarning",
  134. r"-W ignore:in 3\.x, __getslice__:DeprecationWarning",
  135. r"-W ignore:buffer\(\) not supported in 3\.x:DeprecationWarning",
  136. r"-W ignore:CObject type is not supported in 3\.x:DeprecationWarning",
  137. r"-W ignore:comparing unequal types not supported in 3\.x:DeprecationWarning",
  138. r"-W ignore:the commands module has been removed in Python 3\.0:DeprecationWarning",
  139. r"-W ignore:The 'new' module has been removed in Python 3\.0:DeprecationWarning",
  140. ]
  141. if doctests:
  142. raise ValueError("Doctests not supported")
  143. if extra_argv:
  144. pytest_args += list(extra_argv)
  145. if verbose > 1:
  146. pytest_args += ["-" + "v"*(verbose - 1)]
  147. if coverage:
  148. pytest_args += ["--cov=" + module_path]
  149. if label == "fast":
  150. pytest_args += ["-m", "not slow"]
  151. elif label != "full":
  152. pytest_args += ["-m", label]
  153. if durations >= 0:
  154. pytest_args += ["--durations=%s" % durations]
  155. if tests is None:
  156. tests = [self.module_name]
  157. pytest_args += ["--pyargs"] + list(tests)
  158. # run tests.
  159. _show_numpy_info()
  160. try:
  161. code = pytest.main(pytest_args)
  162. except SystemExit as exc:
  163. code = exc.code
  164. return code == 0