Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes15kdownloads
conftest.py249 linesDownload Raw Back to numpy
1"""
2Pytest configuration and fixtures for the Numpy test suite.
3"""
4import os
5import sys
6import tempfile
7import warnings
8from contextlib import contextmanager
9from pathlib import Path
10
11import hypothesis
12import pytest
13
14import numpy
15from numpy._core._multiarray_tests import get_fpu_mode
16from numpy.testing._private.utils import NOGIL_BUILD
17
18try:
19    from scipy_doctest.conftest import dt_config
20    HAVE_SCPDT = True
21except ModuleNotFoundError:
22    HAVE_SCPDT = False
23
24try:
25    import pytest_run_parallel  # noqa: F401
26    PARALLEL_RUN_AVALIABLE = True
27except ModuleNotFoundError:
28    PARALLEL_RUN_AVALIABLE = False
29
30_old_fpu_mode = None
31_collect_results = {}
32
33# Use a known and persistent tmpdir for hypothesis' caches, which
34# can be automatically cleared by the OS or user.
35hypothesis.configuration.set_hypothesis_home_dir(
36    os.path.join(tempfile.gettempdir(), ".hypothesis")
37)
38
39# We register two custom profiles for Numpy - for details see
40# https://hypothesis.readthedocs.io/en/latest/settings.html
41# The first is designed for our own CI runs; the latter also
42# forces determinism and is designed for use via np.test()
43hypothesis.settings.register_profile(
44    name="numpy-profile", deadline=None, print_blob=True,
45)
46hypothesis.settings.register_profile(
47    name="np.test() profile",
48    deadline=None, print_blob=True, database=None, derandomize=True,
49    suppress_health_check=list(hypothesis.HealthCheck),
50)
51# Note that the default profile is chosen based on the presence
52# of pytest.ini, but can be overridden by passing the
53# --hypothesis-profile=NAME argument to pytest.
54_pytest_ini = os.path.join(os.path.dirname(__file__), "..", "pytest.ini")
55hypothesis.settings.load_profile(
56    "numpy-profile" if os.path.isfile(_pytest_ini) else "np.test() profile"
57)
58
59# The experimentalAPI is used in _umath_tests
60os.environ["NUMPY_EXPERIMENTAL_DTYPE_API"] = "1"
61
62def pytest_configure(config):
63    config.addinivalue_line("markers",
64        "valgrind_error: Tests that are known to error under valgrind.")
65    config.addinivalue_line("markers",
66        "leaks_references: Tests that are known to leak references.")
67    config.addinivalue_line("markers",
68        "slow: Tests that are very slow.")
69    config.addinivalue_line("markers",
70        "slow_pypy: Tests that are very slow on pypy.")
71    if not PARALLEL_RUN_AVALIABLE:
72        config.addinivalue_line("markers",
73            "parallel_threads(n): run the given test function in parallel "
74            "using `n` threads.",
75        )
76        config.addinivalue_line("markers",
77            "iterations(n): run the given test function `n` times in each thread",
78        )
79        config.addinivalue_line("markers",
80            "thread_unsafe: mark the test function as single-threaded",
81        )
82
83
84def pytest_addoption(parser):
85    parser.addoption("--available-memory", action="store", default=None,
86                     help=("Set amount of memory available for running the "
87                           "test suite. This can result to tests requiring "
88                           "especially large amounts of memory to be skipped. "
89                           "Equivalent to setting environment variable "
90                           "NPY_AVAILABLE_MEM. Default: determined"
91                           "automatically."))
92
93
94gil_enabled_at_start = True
95if NOGIL_BUILD:
96    gil_enabled_at_start = sys._is_gil_enabled()
97
98
99def pytest_sessionstart(session):
100    available_mem = session.config.getoption('available_memory')
101    if available_mem is not None:
102        os.environ['NPY_AVAILABLE_MEM'] = available_mem
103
104
105def pytest_terminal_summary(terminalreporter, exitstatus, config):
106    if NOGIL_BUILD and not gil_enabled_at_start and sys._is_gil_enabled():
107        tr = terminalreporter
108        tr.ensure_newline()
109        tr.section("GIL re-enabled", sep="=", red=True, bold=True)
110        tr.line("The GIL was re-enabled at runtime during the tests.")
111        tr.line("This can happen with no test failures if the RuntimeWarning")
112        tr.line("raised by Python when this happens is filtered by a test.")
113        tr.line("")
114        tr.line("Please ensure all new C modules declare support for running")
115        tr.line("without the GIL. Any new tests that intentionally imports ")
116        tr.line("code that re-enables the GIL should do so in a subprocess.")
117        pytest.exit("GIL re-enabled during tests", returncode=1)
118
119# FIXME when yield tests are gone.
120@pytest.hookimpl(tryfirst=True)
121def pytest_itemcollected(item):
122    """
123    Check FPU precision mode was not changed during test collection.
124
125    The clumsy way we do it here is mainly necessary because numpy
126    still uses yield tests, which can execute code at test collection
127    time.
128    """
129    global _old_fpu_mode
130
131    mode = get_fpu_mode()
132
133    if _old_fpu_mode is None:
134        _old_fpu_mode = mode
135    elif mode != _old_fpu_mode:
136        _collect_results[item] = (_old_fpu_mode, mode)
137        _old_fpu_mode = mode
138
139    # mark f2py tests as thread unsafe
140    if Path(item.fspath).parent == Path(__file__).parent / 'f2py' / 'tests':
141        item.add_marker(pytest.mark.thread_unsafe(
142            reason="f2py tests are thread-unsafe"))
143
144
145@pytest.fixture(scope="function", autouse=True)
146def check_fpu_mode(request):
147    """
148    Check FPU precision mode was not changed during the test.
149    """
150    old_mode = get_fpu_mode()
151    yield
152    new_mode = get_fpu_mode()
153
154    if old_mode != new_mode:
155        raise AssertionError(f"FPU precision mode changed from {old_mode:#x} to "
156                             f"{new_mode:#x} during the test")
157
158    collect_result = _collect_results.get(request.node)
159    if collect_result is not None:
160        old_mode, new_mode = collect_result
161        raise AssertionError(f"FPU precision mode changed from {old_mode:#x} to "
162                             f"{new_mode:#x} when collecting the test")
163
164
165@pytest.fixture(autouse=True)
166def add_np(doctest_namespace):
167    doctest_namespace['np'] = numpy
168
169
170if HAVE_SCPDT:
171
172    @contextmanager
173    def warnings_errors_and_rng(test=None):
174        """Filter out the wall of DeprecationWarnings.
175        """
176        msgs = ["The numpy.linalg.linalg",
177                "The numpy.fft.helper",
178                "dep_util",
179                "pkg_resources",
180                "numpy.core.umath",
181                "msvccompiler",
182                "Deprecated call",
183                "numpy.core",
184                "Importing from numpy.matlib",
185                "This function is deprecated.",    # random_integers
186                "Data type alias 'a'",     # numpy.rec.fromfile
187                "Arrays of 2-dimensional vectors",   # matlib.cross
188                "NumPy warning suppression and assertion utilities are deprecated."
189        ]
190        msg = "|".join(msgs)
191
192        msgs_r = [
193            "invalid value encountered",
194            "divide by zero encountered"
195        ]
196        msg_r = "|".join(msgs_r)
197
198        with warnings.catch_warnings():
199            warnings.filterwarnings(
200                'ignore', category=DeprecationWarning, message=msg
201            )
202            warnings.filterwarnings(
203                'ignore', category=RuntimeWarning, message=msg_r
204            )
205            yield
206
207    # find and check doctests under this context manager
208    dt_config.user_context_mgr = warnings_errors_and_rng
209
210    # numpy specific tweaks from refguide-check
211    dt_config.rndm_markers.add('#uninitialized')
212    dt_config.rndm_markers.add('# uninitialized')
213
214    # make the checker pick on mismatched dtypes
215    dt_config.strict_check = True
216
217    import doctest
218    dt_config.optionflags = doctest.NORMALIZE_WHITESPACE | doctest.ELLIPSIS
219
220    # recognize the StringDType repr
221    dt_config.check_namespace['StringDType'] = numpy.dtypes.StringDType
222
223    # temporary skips
224    dt_config.skiplist = {
225        'numpy.savez',    # unclosed file
226        'numpy.matlib.savez',
227        'numpy.__array_namespace_info__',
228        'numpy.matlib.__array_namespace_info__',
229    }
230
231    # xfail problematic tutorials
232    dt_config.pytest_extra_xfail = {
233        'how-to-verify-bug.rst': '',
234        'c-info.ufunc-tutorial.rst': '',
235        'basics.interoperability.rst': 'needs pandas',
236        'basics.dispatch.rst': 'errors out in /testing/overrides.py',
237        'basics.subclassing.rst': '.. testcode:: admonitions not understood',
238        'misc.rst': 'manipulates warnings',
239    }
240
241    # ignores are for things fail doctest collection (optionals etc)
242    dt_config.pytest_extra_ignore = [
243        'numpy/distutils',
244        'numpy/_core/cversions.py',
245        'numpy/_pyinstaller',
246        'numpy/random/_examples',
247        'numpy/f2py/_backends/_distutils.py',
248    ]
249 
codekingpro/portable-devtools · Team Ai