jpayne@68: # Pytest customization jpayne@68: import os jpayne@68: import pytest jpayne@68: import warnings jpayne@68: jpayne@68: import numpy as np jpayne@68: import numpy.testing as npt jpayne@68: from scipy._lib._fpumode import get_fpu_mode jpayne@68: from scipy._lib._testutils import FPUModeChangeWarning jpayne@68: from scipy._lib import _pep440 jpayne@68: jpayne@68: jpayne@68: def pytest_configure(config): jpayne@68: config.addinivalue_line("markers", jpayne@68: "slow: Tests that are very slow.") jpayne@68: config.addinivalue_line("markers", jpayne@68: "xslow: mark test as extremely slow (not run unless explicitly requested)") jpayne@68: config.addinivalue_line("markers", jpayne@68: "xfail_on_32bit: mark test as failing on 32-bit platforms") jpayne@68: try: jpayne@68: import pytest_timeout # noqa:F401 jpayne@68: except Exception: jpayne@68: config.addinivalue_line( jpayne@68: "markers", 'timeout: mark a test for a non-default timeout') jpayne@68: jpayne@68: jpayne@68: def _get_mark(item, name): jpayne@68: if _pep440.parse(pytest.__version__) >= _pep440.Version("3.6.0"): jpayne@68: mark = item.get_closest_marker(name) jpayne@68: else: jpayne@68: mark = item.get_marker(name) jpayne@68: return mark jpayne@68: jpayne@68: jpayne@68: def pytest_runtest_setup(item): jpayne@68: mark = _get_mark(item, "xslow") jpayne@68: if mark is not None: jpayne@68: try: jpayne@68: v = int(os.environ.get('SCIPY_XSLOW', '0')) jpayne@68: except ValueError: jpayne@68: v = False jpayne@68: if not v: jpayne@68: pytest.skip("very slow test; set environment variable SCIPY_XSLOW=1 to run it") jpayne@68: mark = _get_mark(item, 'xfail_on_32bit') jpayne@68: if mark is not None and np.intp(0).itemsize < 8: jpayne@68: pytest.xfail('Fails on our 32-bit test platform(s): %s' % (mark.args[0],)) jpayne@68: jpayne@68: # Older versions of threadpoolctl have an issue that may lead to this jpayne@68: # warning being emitted, see gh-14441 jpayne@68: with npt.suppress_warnings() as sup: jpayne@68: sup.filter(pytest.PytestUnraisableExceptionWarning) jpayne@68: jpayne@68: try: jpayne@68: from threadpoolctl import threadpool_limits jpayne@68: jpayne@68: HAS_THREADPOOLCTL = True jpayne@68: except Exception: # observed in gh-14441: (ImportError, AttributeError) jpayne@68: # Optional dependency only. All exceptions are caught, for robustness jpayne@68: HAS_THREADPOOLCTL = False jpayne@68: jpayne@68: if HAS_THREADPOOLCTL: jpayne@68: # Set the number of openmp threads based on the number of workers jpayne@68: # xdist is using to prevent oversubscription. Simplified version of what jpayne@68: # sklearn does (it can rely on threadpoolctl and its builtin OpenMP helper jpayne@68: # functions) jpayne@68: try: jpayne@68: xdist_worker_count = int(os.environ['PYTEST_XDIST_WORKER_COUNT']) jpayne@68: except KeyError: jpayne@68: # raises when pytest-xdist is not installed jpayne@68: return jpayne@68: jpayne@68: if not os.getenv('OMP_NUM_THREADS'): jpayne@68: max_openmp_threads = os.cpu_count() // 2 # use nr of physical cores jpayne@68: threads_per_worker = max(max_openmp_threads // xdist_worker_count, 1) jpayne@68: try: jpayne@68: threadpool_limits(threads_per_worker, user_api='blas') jpayne@68: except Exception: jpayne@68: # May raise AttributeError for older versions of OpenBLAS. jpayne@68: # Catch any error for robustness. jpayne@68: return jpayne@68: jpayne@68: jpayne@68: @pytest.fixture(scope="function", autouse=True) jpayne@68: def check_fpu_mode(request): jpayne@68: """ jpayne@68: Check FPU mode was not changed during the test. jpayne@68: """ jpayne@68: old_mode = get_fpu_mode() jpayne@68: yield jpayne@68: new_mode = get_fpu_mode() jpayne@68: jpayne@68: if old_mode != new_mode: jpayne@68: warnings.warn("FPU mode changed from {0:#x} to {1:#x} during " jpayne@68: "the test".format(old_mode, new_mode), jpayne@68: category=FPUModeChangeWarning, stacklevel=0)