conftest.py 3.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. # Pytest customization
  2. import os
  3. import pytest
  4. import warnings
  5. import numpy as np
  6. import numpy.testing as npt
  7. from scipy._lib._fpumode import get_fpu_mode
  8. from scipy._lib._testutils import FPUModeChangeWarning
  9. from scipy._lib import _pep440
  10. def pytest_configure(config):
  11. config.addinivalue_line("markers",
  12. "slow: Tests that are very slow.")
  13. config.addinivalue_line("markers",
  14. "xslow: mark test as extremely slow (not run unless explicitly requested)")
  15. config.addinivalue_line("markers",
  16. "xfail_on_32bit: mark test as failing on 32-bit platforms")
  17. try:
  18. import pytest_timeout # noqa:F401
  19. except Exception:
  20. config.addinivalue_line(
  21. "markers", 'timeout: mark a test for a non-default timeout')
  22. def _get_mark(item, name):
  23. if _pep440.parse(pytest.__version__) >= _pep440.Version("3.6.0"):
  24. mark = item.get_closest_marker(name)
  25. else:
  26. mark = item.get_marker(name)
  27. return mark
  28. def pytest_runtest_setup(item):
  29. mark = _get_mark(item, "xslow")
  30. if mark is not None:
  31. try:
  32. v = int(os.environ.get('SCIPY_XSLOW', '0'))
  33. except ValueError:
  34. v = False
  35. if not v:
  36. pytest.skip("very slow test; set environment variable SCIPY_XSLOW=1 to run it")
  37. mark = _get_mark(item, 'xfail_on_32bit')
  38. if mark is not None and np.intp(0).itemsize < 8:
  39. pytest.xfail('Fails on our 32-bit test platform(s): %s' % (mark.args[0],))
  40. # Older versions of threadpoolctl have an issue that may lead to this
  41. # warning being emitted, see gh-14441
  42. with npt.suppress_warnings() as sup:
  43. sup.filter(pytest.PytestUnraisableExceptionWarning)
  44. try:
  45. from threadpoolctl import threadpool_limits
  46. HAS_THREADPOOLCTL = True
  47. except Exception: # observed in gh-14441: (ImportError, AttributeError)
  48. # Optional dependency only. All exceptions are caught, for robustness
  49. HAS_THREADPOOLCTL = False
  50. if HAS_THREADPOOLCTL:
  51. # Set the number of openmp threads based on the number of workers
  52. # xdist is using to prevent oversubscription. Simplified version of what
  53. # sklearn does (it can rely on threadpoolctl and its builtin OpenMP helper
  54. # functions)
  55. try:
  56. xdist_worker_count = int(os.environ['PYTEST_XDIST_WORKER_COUNT'])
  57. except KeyError:
  58. # raises when pytest-xdist is not installed
  59. return
  60. if not os.getenv('OMP_NUM_THREADS'):
  61. max_openmp_threads = os.cpu_count() // 2 # use nr of physical cores
  62. threads_per_worker = max(max_openmp_threads // xdist_worker_count, 1)
  63. try:
  64. threadpool_limits(threads_per_worker, user_api='blas')
  65. except Exception:
  66. # May raise AttributeError for older versions of OpenBLAS.
  67. # Catch any error for robustness.
  68. return
  69. @pytest.fixture(scope="function", autouse=True)
  70. def check_fpu_mode(request):
  71. """
  72. Check FPU mode was not changed during the test.
  73. """
  74. old_mode = get_fpu_mode()
  75. yield
  76. new_mode = get_fpu_mode()
  77. if old_mode != new_mode:
  78. warnings.warn("FPU mode changed from {0:#x} to {1:#x} during "
  79. "the test".format(old_mode, new_mode),
  80. category=FPUModeChangeWarning, stacklevel=0)